调用fclose()触发Segmentation Fault问题求助
问题描述
编写函数读取仅含数字的PREVIOUSSTOP文件,根据数字将info文件定位到对应位置(数字为x则前移x个句子),但调用fclose(stop)时出现Segmentation Fault,文件指针非NULL,gdb调试回溯全为问号,请求修复。
原代码
#include <stdio.h> #include <stdlib.h> int stopnum = 0; void GetInfoFromFile(FILE* info, char* Sentence1) { int i = 0; while (1) { char c; c = fgetc(info); Sentence1[i] = c; if (Sentence1[i] == '.' || Sentence1[i] == '!' || Sentence1[i] == '?') { break; } i++; } Sentence1[i + 1] = '\0'; } void RestartPreviousTrainingSession(FILE* info) { FILE* stop = fopen("PREVIOUSSTOP", "r"); if (stop != NULL) { char* stopstr = malloc(32); fgets(stopstr, 32, stop); int stopint = strtol(stopstr, NULL, 10); stopnum = stopint; char dummysentence[400]; for (int i = 0; i != stopint; i++) { GetInfoFromFile(info, dummysentence); } /* segmentation fault occurs here */ fclose(stop); } else { printf("OOPS\n"); } } int main() { FILE* f = fopen("wiki.train.tokens", "r"); RestartPreviousTrainingSession(f); fclose(f); }
问题分析与修复方案
段错误核心原因是缓冲区溢出破坏了栈上的文件指针stop,具体问题点和修复如下:
1. GetInfoFromFile未处理文件结束与缓冲区越界
- 原代码用
char存储fgetc返回值,无法正确识别EOF(EOF是int类型的-1,若char为无符号类型会被转为255,导致循环无法终止)。 - 未限制写入缓冲区的长度,当句子超长或文件提前结束时,会越界写入
dummysentence,破坏栈上的stop指针等数据。
修复后的GetInfoFromFile:
void GetInfoFromFile(FILE* info, char* Sentence1, int max_len) { if (!info || !Sentence1 || max_len <= 0) { return; } int i = 0; int c; while ((c = fgetc(info)) != EOF) { // 预留最后一个位置存'\0',避免缓冲区溢出 if (i >= max_len - 1) { break; } Sentence1[i] = (char)c; if (Sentence1[i] == '.' || Sentence1[i] == '!' || Sentence1[i] == '?') { i++; break; } i++; } Sentence1[i] = '\0'; }
2. 未检查malloc返回值与内存泄漏
malloc(32)可能失败返回NULL,此时调用fgets会直接崩溃。- 分配的
stopstr未释放,存在内存泄漏。
3. 循环与参数合法性问题
- 原循环用
i != stopint,若stopint为负数会陷入死循环,改为i < stopint并提前判断stopint的合法性。
完整修复代码
#include <stdio.h> #include <stdlib.h> #include <ctype.h> int stopnum = 0; void GetInfoFromFile(FILE* info, char* Sentence1, int max_len) { if (!info || !Sentence1 || max_len <= 0) { return; } int i = 0; int c; while ((c = fgetc(info)) != EOF) { if (i >= max_len - 1) { break; } Sentence1[i] = (char)c; if (Sentence1[i] == '.' || Sentence1[i] == '!' || Sentence1[i] == '?') { i++; break; } i++; } Sentence1[i] = '\0'; } void RestartPreviousTrainingSession(FILE* info) { if (!info) { return; } FILE* stop = fopen("PREVIOUSSTOP", "r"); if (stop != NULL) { char* stopstr = malloc(32); if (!stopstr) { fclose(stop); return; } // 读取失败或为空时直接返回 if (!fgets(stopstr, 32, stop)) { free(stopstr); fclose(stop); return; } // 跳过开头空白字符,确保strtol正确解析 char* ptr = stopstr; while (isspace((unsigned char)*ptr)) { ptr++; } int stopint = strtol(ptr, NULL, 10); // 过滤无效的负数或0 if (stopint <= 0) { free(stopstr); fclose(stop); return; } stopnum = stopint; char dummysentence[400]; for (int i = 0; i < stopint; i++) { GetInfoFromFile(info, dummysentence, sizeof(dummysentence)); // 文件提前结束时终止循环 if (feof(info)) { break; } } free(stopstr); fclose(stop); } else { printf("OOPS\n"); } } int main() { FILE* f = fopen("wiki.train.tokens", "r"); if (f) { RestartPreviousTrainingSession(f); fclose(f); } else { printf("Failed to open wiki.train.tokens\n"); } return 0; }
内容的提问来源于stack exchange,提问作者user17231236
相关产品推荐
相关产品推荐

