使用 fscanf 和 fgetc 读取文本行

Reading text lines with fscanf and fgetc

就这么一个小问题就犯了难。我正在尝试从文件中读取文本。该文件的格式为:

Jim 3 X Y Z 
James 2 A B
Alley 5 D E F G H 

其中整数表示后面的变量个数。 我正在使用 fscanf 读取名称和编号,然后使用 fgetc 读取 char 变量,这样我就可以将它们放入一个数组中。 fscanf 部分工作正常,但我在 fgetc 中遗漏了一些东西。

 do {
    c = fscanf(inputFile, "%s" "%d", word, &inputSize); 
    printf("%s ", word);

    while (c!= '\n')  {
        c = fgetc(inputFile);
        printf("char is:%c ", c);
    }
}while (c != EOF);

这将进入无限循环。所以我试着告诉 fgetc 什么时候停止。

while (c != EOF){
    c = fscanf(inputFile, "%s" "%d", word, &inputSize); 
    printf("%s ", word);
    printf("%d ", inputSize);
    printf("\n");
    for (i =0;i<(inputSize*2);i++) {
            c = fgetc(inputFile) ;
            if (c== ' ') {
            }
            else {
                 printf("char is :%c ", c);
                 printf("\n");
            }
    }

输出变为:

 Jim 3 
 char is :X 
 char is :Y 
 char is :Z 
 James 2 
 char is :A 
 char is :B 
 Alley 5 
 char is :D 
 char is :E 
 char is :F 
 char is :G 
 char is :H 
 Alley 5 
 char is :? 
 char is :? 
 char is :? 
 char is :? 
 char is :? 
 char is :? 
 char is :? 
 char is :? 
 char is :? 
 char is :? 

我搞砸了 fgetc 的哪一部分?另外,为什么 fgetc 在我的第一个例子中没有看到 '\n',而是无限循环?

谢谢

在原始代码中,你有:

char c;   // Per comments
do {
    c = fscanf(inputFile, "%s" "%d", word, &inputSize); 
    printf("%s ", word);

    while (c!= '\n')  {
        c = fgetc(inputFile);
        printf("char is:%c ", c);
    }
} while (c != EOF);

在您阅读 Alley 数据后的换行符之前,此代码可以正常工作。然后你回到循环的顶部,用 fscanf() 读取一些数据。由于没有数据,fscanf() returns EOF,但是你继续打印之前在 wordinputSize 中的内容。然后你进入一个无限循环,因为 fgetc() returns EOF,它不是 \n,所以你一次又一次地尝试,然后......

修复:

  1. fgetc() return 是 int,而不是 char。在普通 char 是有符号类型的系统上,这意味着您将有效字符(通常是 ÿ、U+00FF、带分音符的拉丁文小写字母 Y)误认为是 EOF。在普通 char 是无符号类型的系统上,没有任何内容与 EOF 匹配。这两种行为都不正确。
  2. 测试 EOF 或换行符;一直想着。
  3. 测试 fscanf() 中的 return;如果不是 2,则说明出错了。

而且我会使用顶部检查 while 循环而不是底部检查 do … while 循环。有时会出现 do … while 循环;在我看来,这不是其中之一。

修改后的代码分析类似。您的代码是:

char c = 0;
while (c != EOF){
    c = fscanf(inputFile, "%s" "%d", word, &inputSize); 
    printf("%s ", word);
    printf("%d ", inputSize);
    printf("\n");
    for (i =0;i<(inputSize*2);i++) {
            c = fgetc(inputFile) ;
            if (c== ' ') {
            }
            else {
                 printf("char is :%c ", c);
                 printf("\n");
            }
    }
}

同样,您需要检查由 fscanf() 编辑的值 return,如果它不是 2,则退出循环。前三个 printf() 调用可以组合成一。 在你第一次读取Alley的数据后,fscanf() returns EOF,但你忽略了它并再次打印数据。然后你进入 fgetc() 循环,它将 EOF 映射到 ÿ (0xFF) 但这不是空白,所以你打印它(就其本身而言,0xFF 不是 UTF-8 中的有效字节,这可能占打印的问号)。当您完成 10 次迭代后,c 包含一个扩展到 EOF 的代码,因此循环终止。

修复:

  • 与之前大致相同。
  • 使用int char;
  • 在继续之前检查 fscanf() 中的 return。
  • 检查 fgetc() 循环中的所需字符或 EOF。

原始代码的可能修复:

int c;
while (fscanf(inputFile, "%s%d", word, &inputSize) == 2)
{
    printf("%s (%d)\n", word, inputSize);

    while ((c = getc(inputFile)) != EOF && c != '\n')
    {
        if (c != ' ')
            printf("char is: %c\n", c);
    }
}