AoC第一日代码触发Segmentation fault问题求助
问题排查:Advent of Code第一日程序Segmentation Fault错误
问题背景
正在完成Advent of Code(AoC)第一日任务,统计每个精灵的总卡路里摄入量,输入数据来自txt文件。代码可完成4次统计,但第五次触发Segmentation fault,怀疑与line变量相关,尝试释放并重新分配line内存后无改善。
运行输出
Elf number 0 calorie intake was 47524
Elf number 1 calorie intake was 18774
Elf number 2 calorie intake was 11597
Elf number 3 calorie intake was 10625
[1] 97205 segmentation fault ./a.out
代码实现
#include <stdio.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #define BUFF 500 int array[BUFF]; void read_file(FILE *file, char *line, const size_t lineSize, int counter) { int calorie = 0; while (strlen(fgets(line, lineSize, file)) != 1) { calorie += atoi(line); } printf("Elf number %d calorie intake was %d\n\n", counter, calorie); } int main() { int counter = 0; int calorie = 0; const size_t line_size = 6; FILE *fp = fopen("example.txt", "r"); while (counter <= 500) { char * line = malloc(line_size); read_file(fp, line, line_size, counter); counter++; free(line); } return 1; }
输入文件(前50行)
4514
8009
6703
1811
4881
3905
3933
9436
43323059
15715
11597
10625
84864556
10613
4087
11287
12020
14125320
9757
10646
7373
1197
3486
435916319
22687
52726167
2478
4950
5513
6113
2739
6805
4488
6555
27522198
2528
3432
2218
3283
1400
1932
3438
1834
1050
4766
5218
3033
3410
问题原因分析
- 未检查文件打开状态:
fopen后未判断fp是否为NULL,若文件不存在或权限不足,后续操作直接触发崩溃。 fgets返回值未做空指针校验:当文件读到末尾时,fgets返回NULL,此时调用strlen(NULL)属于未定义行为,直接触发Segmentation Fault。第四次统计后,文件读取到第五个精灵的内容阶段,某次fgets返回NULL导致错误。- 空行判断逻辑错误:
strlen(fgets(...)) !=1的判断不严谨,空行实际是包含\n的字符串,长度为1,但如果fgets失败返回NULL,strlen(NULL)直接崩溃。 - 循环终止条件不合理:
main中while (counter <=500)强制循环501次,但输入文件的精灵数量远少于500,文件读完后继续调用fgets会持续返回NULL,触发错误。
修复方案
修复后的代码
#include <stdio.h> #include <string.h> #include <stdlib.h> #define BUFF 500 int array[BUFF]; void read_file(FILE *file, char *line, const size_t lineSize, int counter) { int calorie = 0; char *ret; while ((ret = fgets(line, lineSize, file)) != NULL) { // 去除换行符 line[strcspn(line, "\n")] = '\0'; // 判断是否为空行(精灵数据分隔符) if (strlen(line) == 0) { break; } calorie += atoi(line); } // 仅在有效读取到数据时打印 if (calorie != 0 || ret != NULL) { printf("Elf number %d calorie intake was %d\n\n", counter, calorie); } } int main() { int counter = 0; const size_t line_size = 10; // 扩大缓冲区,兼容更长数字 FILE *fp = fopen("example.txt", "r"); // 检查文件是否成功打开 if (fp == NULL) { perror("Failed to open file"); return 1; } // 循环读取直到文件结束 while (1) { char *line = malloc(line_size); if (line == NULL) { perror("Failed to allocate memory"); fclose(fp); return 1; } read_file(fp, line, line_size, counter); // 检测文件是否已读完 if (feof(fp)) { free(line); break; } counter++; free(line); } fclose(fp); return 0; }
关键修复点
- 添加文件打开成功校验,避免空指针操作。
- 先判断
fgets返回值是否为NULL,再处理字符串,规避strlen(NULL)的未定义行为。 - 正确处理空行:先去除换行符,再通过字符串长度判断是否为精灵数据分隔符。
- 调整循环终止条件,文件读取完毕后自动退出,不再强制循环500次。
- 扩大
line_size到10,为更长数字预留空间,避免缓冲区溢出。 - 添加内存分配失败校验,增强程序健壮性。
- 读取结束后关闭文件,避免资源泄漏。
内容的提问来源于stack exchange,提问作者Aiden Hanney
相关产品推荐
相关产品推荐

