C如何处理EOF?

时间:2013-04-07 05:01:09

标签: c feof

#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

我做错了什么?

2 个答案:

答案 0 :(得分:4)

自行测试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会读取空格字符;除非每行没有空格,否则它不会读取行。

使用feof()来区分转换失败,I / O错误和fscanf()等操作报告故障后的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和错误(大致如图所示)。

答案 1 :(得分:2)

点击 文件末尾之后

feof不会告诉您已经到达文件的末尾,直到。检查fscanf的结果(返回值)。它会告诉你什么时候它不能再读了。如果fscanf到达文件末尾,将返回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个值。