C语言统计文件单词次数程序为何触发段错误?
C程序段错误原因分析
问题背景
编写了一个统计目标单词在ham/spam消息中出现次数的C程序,单独测试各函数正常,但整合后触发段错误。编译时仅提示function returns address of local variable警告。程序代码如下:
#include <stdio.h> #include <string.h> int *countSH(char *filename, char *SentWord) { //opening file and checking whether it opens FILE *file = fopen(filename, "r"); if (file == NULL) { perror("error while opening file"); return NULL; } char line[500]; //line lenght = 500 int hams = 0; int spams = 0; char *token = NULL; const char *word = SentWord; char *lineDupe; while(1) { if (feof(file)) { break; //breaking the loop when getting to the end of the file } if (fgets(line, sizeof(line), file) != NULL) { //if line != NULL lineDupe = strdup(line); token = strtok(lineDupe, " \t\n"); while (token != NULL) { if (strcmp(token, word) == 0) { if (line[0] == 'h') { //if line starts with h (ham) hams++; } else { //else it starts with s (spam) spams = spams + 1; } } token = strtok(NULL, " \t\n"); } } } int countsh[2] = { hams, spams }; if (hams == 0 && spams == 0) { printf("This word doesn’t occur in the text!"); } else { printf("The word '%s' appears %d times in ham messages and %d times in spam messages."); } return countsh; } //this function gets the user input and saves the word for searching char *getWord() { static char word[256]; printf("Please enter a word to search for:\t"); scanf("%255s", word); return word; } int main() { char *searchWord = getWord(); //assigning the searchword we got from the user to a var char *file = "preprocessed_dataset.txt"; int *word_in_sh = countSH(file, searchWord); return 0; }
编译警告:
try1_3.c: In function ‘countSH’: try1_3.c:50:2: warning: function returns address of local variable [-Wreturn-local-addr] return countsh;
段错误触发原因
1. printf语句缺少必要参数
这是触发段错误的直接原因:
在countSH函数的else分支中,printf格式化字符串包含%s、%d、%d三个占位符,但没有传入对应的SentWord、hams、spams参数。这种情况下,程序会从栈上读取随机数据,导致栈访问越界,直接触发段错误。
2. 返回局部变量的地址
countSH函数中定义的int countsh[2]是栈上的局部变量,当函数执行完毕返回时,该变量所在的栈帧会被销毁,返回的地址变为野指针。虽然main函数中没有直接解引用这个指针,但这种行为属于未定义行为,可能间接导致程序崩溃。
3. feof的错误使用方式
当前循环先判断feof(file)再调用fgets,这会导致逻辑错误:当fgets读取到文件末尾时,feof标志才会被设置,此时循环会多执行一次,可能处理无效的空数据,引发未定义行为。
4. strdup内存泄漏(非段错误直接原因,但需修复)
每次循环中使用strdup复制行数据,但没有调用free(lineDupe)释放内存,会导致内存泄漏。
修复建议
- 补全printf的参数:将else分支的printf改为:
printf("The word '%s' appears %d times in ham messages and %d times in spam messages.", SentWord, hams, spams); - 避免返回局部变量地址:可以改用动态分配内存(
malloc)存储结果,或者通过指针参数传递结果; - 修正feof的使用逻辑,用fgets返回值控制循环:
while (fgets(line, sizeof(line), file) != NULL) { // 处理行数据 } - 每次使用strdup后,调用
free(lineDupe)释放内存。
内容的提问来源于stack exchange,提问作者SUPERoya
相关产品推荐
相关产品推荐

