You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 05:20:28