C语言使用malloc存储字符串出现段错误,寻求故障排查
段错误原因分析与代码修正
核心问题梳理
你的代码存在多处指针使用错误与未定义行为,直接导致了段错误,具体问题如下:
- 结构体定义错误:原代码中
struct product{...}product;是定义了一个名为product的结构体变量,而非类型别名,后续使用时容易混淆类型与变量。 allocList函数问题:返回类型声明为struct product但无return语句,触发未定义行为;仅为数组第一个元素的regal分配内存,其余元素的regal均为野指针。isInList函数参数与逻辑错误:参数误用二级指针struct product**,实际应使用指向结构体数组的一级指针struct product*;首次调用时直接访问未初始化的name指针(野指针)调用strcmp,引发段错误。insert函数参数传递与指针访问错误:调用isInList时错误传递参数(将二级指针直接传入、传值而非传地址);访问结构体数组元素时误用二级指针索引,导致指针越界。
修正后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> // 使用typedef定义结构体类型别名,简化后续代码 typedef struct product { int *regal; char *name; } product; // 初始化结构体数组,为每个元素的regal分配内存并初始化name为NULL void allocList(product **list, int alloc) { *list = malloc(sizeof(product) * alloc); for (int i = 0; i < alloc; i++) { (*list)[i].regal = calloc(100, sizeof(int)); (*list)[i].name = NULL; // 初始化name避免野指针 } } // 检查产品是否已存在于列表中 int isInList(product *list, int listSize, char *item, int *itemIndex) { for (int i = 0; i < listSize; i++) { // 先判断name是否有效,再比较字符串 if (list[i].name != NULL && !strcmp(item, list[i].name)) { *itemIndex = i; return 1; } } return 0; } // 插入新产品(不存在则插入) int insert(product **list, int alloc, int *listSize, char *item, int regalIndex) { int itemIndex = 0; // 传递正确的结构体数组首地址与列表长度指针 if (isInList(*list, *listSize, item, &itemIndex)) { return 0; } // 检查数组是否已满,避免越界 if (*listSize >= alloc) { printf("数组已满,无法插入新元素\n"); return 0; } // 分配字符串内存并复制,正确访问结构体数组元素 (*list)[*listSize].name = malloc(strlen(item) + 1); strcpy((*list)[*listSize].name, item); (*list)[*listSize].regal[0] = regalIndex; // 示例:设置regal索引值 (*listSize)++; return 1; } int main() { product *list = NULL; int listAlloc = 2000; int listSize = 0; allocList(&list, listAlloc); char *str = "abcd"; char *str1 = "bcd"; insert(&list, listAlloc, &listSize, str, 1); insert(&list, listAlloc, &listSize, str, 1); // 重复插入,返回0 insert(&list, listAlloc, &listSize, str1, 1); // 验证插入结果 for (int i = 0; i < listSize; i++) { printf("产品%d:%s,regal[0]=%d\n", i+1, list[i].name, list[i].regal[0]); } // 释放所有分配的内存,避免泄漏 for (int i = 0; i < listAlloc; i++) { free(list[i].name); free(list[i].regal); } free(list); return 0; }
关键修正说明
- 结构体定义:用
typedef创建类型别名product,简化类型声明与使用。 - 数组初始化:
allocList改为void返回类型,循环为每个结构体元素分配regal内存,并初始化name为NULL,避免后续访问野指针。 - 存在性检查:
isInList改用一级指针访问结构体数组,先判断name是否有效再调用strcmp,避免非法内存访问。 - 插入逻辑:修正参数传递方式,添加数组满员检查,使用
(*list)[*listSize]正确访问结构体数组的目标元素。 - 内存管理:添加完整的内存释放代码,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Aaron7
相关产品推荐
相关产品推荐

