使用fgets/strtok逐行处理输入文件时循环未执行的问题排查
C程序中fgets循环无法进入及代码问题修复
核心问题与错误分析
你的程序无法进入getWords的fgets循环,以及后续逻辑异常,是由多个代码错误共同导致的:
1. 文件打开逻辑矛盾
main函数中硬编码打开"input.txt",但错误提示却使用argv[1],若你通过命令行指定输入文件,会导致实际打开的文件与预期不符;若input.txt不存在,fopen返回NULL,后续fgets循环自然无法执行。
2. 变量类型错误
getWords函数中char p = NULL;定义错误,p需要是char*类型(用于接收strtok的返回值),char类型无法存储指针地址,导致后续strtok的赋值与判断完全失效。
3. clean函数存在严重未定义行为
char *dst;未初始化,直接使用*dst++会访问野指针,引发程序崩溃或异常。*dst = 0;未被包含在if语句的花括号内,会在每次循环时执行,且dst未初始化,操作非法。- 返回
dst错误,此时dst指向处理后字符串的末尾,而非起始位置,后续strcpy会复制空内容或垃圾数据。
4. getWords函数逻辑冗余且缺失返回值
if (p == NULL)的判断完全多余,每行读取后都需要重新调用strtok分割当前行内容,无需依赖上一次的p值。- 函数末尾未返回
word_cnt,导致main中获取的num_words为随机值。
5. 数组维度定义颠倒
char words[MAXC][MAXW]维度错误,应定义为char words[MAXW][MAXC]——需要存储最多MAXW个单词,每个单词最多MAXC个字符,原定义会导致存储单词时越界。
修正后的完整代码
// This program reads all lines of an input file and generates // a report including: // Number of words in the file // Which word size occurs the most and how many times // Largest word length and its frequency // All words of the longest word length of the file // (duplicates not reported) #include <stdio.h> #include <ctype.h> #include <string.h> #define MAXW 300 // max total words #define MAXC 17 // max chars in a word #define MAXLINEW 82 // max chars to a line #define MAXLINE 30 // max number of lines void clean(char *src); int getWords(char (*words)[MAXC], FILE *f); int main(int argc, char **argv) { // 修正数组维度:MAXW个单词,每个MAXC字符 char words[MAXW][MAXC] = {{0}}; int num_words = 0; // 检查命令行参数 if (argc < 2) { fprintf(stderr, "Usage: %s <input-file>\n", argv[0]); return 1; } FILE *f = fopen(argv[1], "r"); if (!f) { fprintf(stderr, "ERROR: Unable to open file '%s'.\n", argv[1]); return 1; } num_words = getWords(words, f); printf("Num words = %d\n", num_words); fclose(f); return 0; } // 修正clean函数:直接修改原字符串,去掉标点并转小写 void clean(char *src) { char *dst = src; // 用dst指向原字符串起始位置 for (; *src; ++src) { if (!ispunct((unsigned char)*src)) { *dst++ = tolower((unsigned char)*src); } } *dst = '\0'; // 在处理后的字符串末尾添加结束符 } int getWords(char (*words)[MAXC], FILE *f) { int word_cnt = 0; char *p; char buf[MAXLINEW]; static const char delims[] = " \n\t"; // 增加制表符作为分隔符,更合理 while (fgets(buf, MAXLINEW, f)) { // 分割当前行的单词 p = strtok(buf, delims); while (p && word_cnt < MAXW) { // 增加单词数量上限检查,防止越界 clean(p); // 确保单词长度不超过MAXC-1(留位置存结束符) if (strlen(p) < MAXC) { strcpy(words[word_cnt], p); word_cnt++; } p = strtok(NULL, delims); } } return word_cnt; // 返回实际单词数量 }
关键修改说明
- 修正文件打开逻辑,通过命令行参数指定输入文件,增加参数合法性检查。
- 修复变量类型错误,将
char p改为char* p。 - 重写
clean函数,直接在原字符串上修改,避免野指针问题,正确添加字符串结束符。 - 移除
getWords中冗余的if (p == NULL)判断,增加单词数量和长度的边界检查,防止数组越界。 - 修正数组维度,确保能正确存储所有单词。
- 为
main和getWords函数添加正确的返回值。
内容的提问来源于stack exchange,提问作者Lumi
相关产品推荐
相关产品推荐

