PAYATHON 2026

到达 EOF 后继续调用 fscanf 安全吗?

数据小陈

结论

只要 FILE *、格式字符串和参数有效,调用 fscanf 就是安全的。读到文件末尾后,fscanf 会返回 EOF。之后继续读取,通常仍会返回 EOF,直到清除 EOF 状态或重新定位流。解析时不能只在跳过当前行的例程中检查 EOF;每次调用 fscanf 后,都要检查返回值,确认所需字段是否全部读到。

检查每次调用的返回值

fscanf 返回成功赋值的项目数。如果在给任何项目赋值前就遇到输入结束,它会返回 EOF;如果输入与格式不匹配,可能返回 0;如果只读到部分项目,则返回已赋值的数量。因此,可以通过返回值判断是否遇到 EOF,以及解析是否完整。

例如,下面的代码预期每行包含两个整数:

#include <stdio.h>

static void skip_line(FILE *fp)
{
    int ch;
    while ((ch = fgetc(fp)) != '\n' && ch != EOF) {
        /* 丢弃当前行剩余内容 */
    }
}

int main(void)
{
    FILE *fp = fopen("input.txt", "r");
    if (fp == NULL) {
        return 1;
    }

    int a, b;
    for (;;) {
        int rc = fscanf(fp, "%d %d", &a, &b);

        if (rc == EOF) {
            break;
        }
        if (rc != 2) {
            skip_line(fp);
            continue;
        }

        /* 仅在两个整数都读到后使用 a 和 b */
    }

    fclose(fp);
    return 0;
}

rc == EOF 表示本次读取在完成任何赋值前就遇到了输入结束或读取错误。rc != 2 表示这一行没有按预期读到两个整数。跳过该行的剩余内容后再继续,可以避免格式不匹配时反复读取同一个字符。

为什么不能只在跳行时检查

一行解析到一半时可能遇到 EOF,输入格式也可能在文件末尾之前就出错。如果不检查当前 fscanf 的返回值,程序可能会使用尚未赋值的变量,或者在匹配失败后卡在原处。跳行例程中的 EOF 检查只能让跳过操作在 EOF 时结束,无法说明此前的字段是否成功读取。

如果只需判断是否到达 EOF,可以检查 fscanf 是否返回 EOF。若要区分文件结束和读取错误,还应调用 ferror(fp)。可以用 clearerr(fp) 清除文件结束状态;要继续读取,通常还需要重新定位流,或确保还有其他输入可供读取。

备注:内容仅供参考。