【问题标题】:How does C handle EOF? [duplicate]C如何处理EOF? [复制]
【发布时间】:2013-03-29 08:25:17
【问题描述】:
#include <stdio.h>

int main()
{
    FILE* f=fopen("book2.txt","r");
    char a[200];
    while(!feof(f))
    {
        fscanf(f,"%s",a);
        printf("%s ",a);
        printf("%d\n",ftell(f));
    }
    fclose(f);
    return 0;
}   

我有上面的代码。 book2.txt 包含“abcdef abcdef”,光标移动到换行符(即:abcdef abcdef\n)。我得到以下结果。

abcdef 6
abcdef 13
abcdef 19

我希望得到

abcdef 6
abcdef 13
15

我做错了什么?

【问题讨论】:

标签: c feof


【解决方案1】:

feof 直到点击文件末尾之后才会告诉您您已经点击了文件末尾。检查来自fscanf 的结果(返回值)。它会告诉您何时无法再读取。如果fscanf 到达文件末尾,it 将返回 EOF(并且feof 将在这发生后返回 true)。

现在只是为了好玩,看看这种方式。永远不要这样做。

while(1) {
    switch(fscanf(f,"%s",a)){
        case 1: 
            printf("%s ",a);
            printf("%d\n",ftell(f));
            continue;
        case EOF:
            break;
    }
    break;
}

这种方式是错误的,因为它聪明。如果再遇到一些情况,整个循环的行为将变得非常难以辨别(例如this program)。使用fscanf,您真的只需要知道您是否获得了继续所需的所有数据。让下一个输入读取函数在找到 EOF 时对其进行处理。 这个调用fscanf需要填充x个值所以,

if (fscanf(f,"%d %d %d", &i, &j, &k) != 3)
    /* cannot continue. need i j k values for next computation */

然后做你的错误响应,或者退出循环,或者你的程序接下来需要做的任何事情。但是如果fscanf 返回的不是 3,它就没有读取 3 个值。

【讨论】:

  • 请向我们解释这种方式有什么问题,以便我们知道该怎么做,而你有我的投票权。
  • 好的。我试过了。我想我在写的时候成熟了一点。 :)
  • WTF 有一个只循环一次的循环,这与这个问题无关。考虑int foo; for (foo = fscanf(stdin, "%s", bar); foo == 1; foo = fscanf(stdin, "%s", bar)) { printf("%s\n", bar); }... 在这个循环之后,可以检查返回的值,看看它是匹配失败(这种格式字符串不会发生)还是导致 fscanf 返回非 1 的读取失败。
  • 我不明白你在说什么。 WTF 在哪里?
  • 我想我想说的是:旨在教人们如何以正确的方式做事,而不是教人们什么是不正确的方式。 “The WTF”指的是一个名为“the daily WTF”的网站。
【解决方案2】:

测试 I/O 操作本身;不要使用feof(),除非你在写 Pascal(而且 C 不是 Pascal!)

#include <stdio.h>

int main(void)
{
    FILE *f = fopen("book2.txt", "r");
    char a[200];
    if (f != 0)
    {
        while (fscanf(f, "%199s", a) == 1)
        {
            printf("%s ", a);
            printf("%ld\n", ftell(f));
        }
        putchar('\n');
        fclose(f);
    }
    return 0;
}

请注意,修改后的代码在使用之前会测试f,并通过指定字符串在转换规范中的长度来防止缓冲区溢出。请注意,%s 最多读取一个空格字符;除非每行没有空格,否则它不会读取行。

fscanf() 等操作报告故障后,您使用feof() 来区分转换失败、I/O 错误和EOF。例如:

#include <stdio.h>

int main(void)
{
    FILE *f = fopen("book2.txt", "r");
    char a[200];
    if (f != 0)
    {
        while (fscanf(f, "%199s", a) == 1)
        {
            printf("%s ",a);
            printf("%ld\n", ftell(f));
        }
        putchar('\n');
        if (feof(f))
            printf("EOF\n");
        else if (ferror(f))
            printf("I/O error\n");
        else
            printf("Conversion failed\n");
        fclose(f);
    }
    return 0;
}

使用%s,您不会出现转换失败,而且 I/O 错误也不太可能发生。但是,如果转换说明符是 %d,则数据中的标点符号可能会让您收到“转换失败”。

在超过 25 年的 C 编码中,我的代码中有 2 个地方在数千个文件中使用了 feof()(几个月前我使用了 check),在这两种情况下,代码区分 EOF 和错误(大致如图所示)。

【讨论】:

  • 您的 ftell() 参数的格式说明符错误。 ftell() 返回 long,而不是 int
  • @Wiz:真;我从问题中复制并没有仔细检查该行的内容。我会修复;谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-01-09
  • 1970-01-01
  • 2010-10-04
  • 2018-05-11
  • 2012-06-25
  • 2011-06-08
  • 1970-01-01
相关资源
最近更新 更多