C语言结构体读取文件时触发Segmentation Fault 11问题排查
触发Segmentation Fault 11的核心原因
- 直接触发崩溃的诱因:
sscanf传入非法内存地址sscanf的入参要求是,格式字符串之后的所有参数,必须是指向待写入变量的有效内存地址。代码中p[i].serialNum、p[i].price都是int类型的结构体成员,初始化后这两个值为0,代码直接把这两个0值当做内存地址传给sscanf。当sscanf尝试把解析到的整数写入地址为0的非法内存空间时,立刻触发内存访问违规,和你观察到的“仅打印第一行内容就崩溃”的现象完全匹配:因为fputs打印行的操作在sscanf之前执行,打印完第一行执行sscanf时就触发了崩溃。 - 其他会引发崩溃的潜在bug
- 循环缺少递增逻辑:循环体中从未对
i执行i++操作,就算修复了sscanf的地址问题,i也会永远停留在0,造成死循环读取文件。 - 数组访问越界风险:定义的结构体数组
p长度为4,合法下标范围是0~3,但循环的终止条件写的是i < 6,就算补全了i的递增逻辑,当i增长到4、5时,会越界访问数组外的非法内存,同样会触发段错误。
- 循环缺少递增逻辑:循环体中从未对
- 不引发崩溃但导致功能失效的逻辑错误
sscanf的格式串"%d %s %d %s"一共只有4个占位符,正常解析成功时返回值为4,但代码中判断条件写的是返回值等于5,这个判断永远无法成立,根本不会进入存储信息的分支。
修正后的参考代码
typedef struct{ int serialNum; char giftName[50]; int price; char store[50]; } product; void read_File(const char *filename) { // 原代码存在强制覆盖入参的逻辑:filename = "items.txt" // 如果需要使用函数入参传入的文件名,需要移除上述赋值语句 const int product_arr_len = 4; product p[product_arr_len] = {0}; int i = 0; FILE *file = fopen(filename, "r"); if (file){ char line[100]; // 循环终止条件和数组长度匹配,避免越界 while(fgets(line, sizeof line, file) && i < product_arr_len){ fputs(line, stdout); // 给int类型成员补取地址符,返回值判断和实际占位符数量匹配 if (sscanf(line, "%d %s %d %s", &p[i].serialNum, p[i].giftName, &p[i].price, p[i].store) == 4) { printf("Storing information in structure complete.\n"); } i++; } fclose(file); } else{ perror(filename); } }
内容的提问来源于stack exchange,提问作者Isis Frazier
相关产品推荐
相关产品推荐

