【问题标题】:EOF is not working properly in c as well printing is also absurdEOF 在 c 中不能正常工作,打印也是荒谬的
【发布时间】:2017-09-13 21:28:06
【问题描述】:

在我的代码中,我从控制台获取输入并将其写入文件“测试”,我从控制台获取输入,直到遇到 EOF ((fscanf(stdin,"%c %s %d % f",&a,b,&c,&d))!=EOF) 因为如果我们在扫描时输入 EOF(ctrl+Z),fscanf 返回 EOF。但是我的代码在获取一个 EOF 后并没有停止,它需要两个或三个 EOF 来扫描终止。我手动检查第一个 EOF 没有返回任何内容,第二个 EOF 返回一个,第三个 EOF 返回-1。扫描终止后它也会打印荒谬的东西。 我的代码如下所示

#include<stdio.h>
int main()
{
    FILE *f;
    char a,b[100];
    int c;
    float d;
    f=fopen("test","w");
    if(f==NULL)
        printf("error");
    while((fscanf(stdin,"%c %s %d %f",&a,b,&c,&d))!=EOF)
        fprintf(f,"%c%s%d%f",a,b,c,d);
    fclose(f);
    f=fopen("test","r");
    while((fscanf(f,"%c%s%d%f",&a,b,&c,&d))!=EOF)
        printf("%c %s %d %f\n",a,b,c,d);
    return 0;
}

【问题讨论】:

  • 请提供您的准确测试输入
  • 如果您不在空行上,可能与按两次 ^Z 模拟 EOF 有关。当 ^Z 作为第一个输入时,您的程序会按预期运行。
  • 至于为什么要按两次以上,是因为 fscanf 只有在第一次匹配转换或失败发生之前到达文件末尾时才返回 EOF。所以你已经给出了一些输入,然后按 ^Z(2 次),然后 fscanf 不会返回 EOF。

标签: c file input output eof


【解决方案1】:

发布的代码没有正确处理换行符。第二行输入将以\n 开头,位于上一行输入的左侧,并且此字符由%c 转换说明符匹配。当EOF 从键盘发出信号时,这个匹配已经完成,所以fscanf() 函数返回1 而不是EOF。第二次发出EOF 信号时,输入流中没有剩余字符,不进行匹配并返回EOF

这也部分解释了乱码输出,因为写入文件的第二行以 \n 字符而不是预期字符开头。此外,写入文件的对fprintf() 的调用不会在字段之间留下空格,因此稍后尝试读回数据失败。

此外,当代码第一次检查文件是否已成功打开时,如果没有,则不执行任何操作。这是已发布代码的更正版本,如果文件无法打开,则会退出并显示错误消息,如果文件无法关闭,也会打印错误消息,如果文件在重新打开之前无法关闭,则会退出。

fscanf() 格式字符串的开头添加了一个空格,以便跳过包括换行符在内的初始空格。在fprintf() 格式字符串的指令之间放置了空格,最后是\n,以便后续调用fscanf() 可以识别这些字段。请注意,如果fscanf() 格式字符串中没有%s 的宽度说明符,则存在缓冲区溢出的风险。但是即使有了这样的改进,如果输入的字符串太大,输入也会出现乱码。最好使用fgets()sscanf(),并更仔细地验证输入。

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE *f;
    char a, b[100];
    int c;
    float d;

    f = fopen("test", "w");
    if(f == NULL) {
        fprintf(stderr, "Unable to open file for writing\n");
        exit(EXIT_FAILURE);
    }

    while((fscanf(stdin," %c%99s%d%f", &a, b, &c, &d)) != EOF)
        fprintf(f,"%c %s %d %f\n", a, b, c, d);

    if (fclose(f) != 0) {
        fprintf(stderr, "Unable to close file\n");
        exit(EXIT_FAILURE);
    }

    f = fopen("test", "r");
    if(f == NULL) {
        fprintf(stderr, "Unable to open file for reading\n");
        exit(EXIT_FAILURE);
    }

    while((fscanf(f," %c%99s%d%f", &a, b, &c, &d)) != EOF)
        printf("%c %s %d %f\n", a, b, c, d);

    if (fclose(f) != 0) {
        fprintf(stderr, "Unable to close file\n");
    }

    return 0;
}

这是一个示例交互。换行符终止输入的每一行:

λ> ./a.out
a first 3 3.14 
b second 42 2.71828
a first 3 3.140000
b second 42 2.718280

【讨论】:

  • 非常非常感谢您的回答。我不期待这样的回答。但是,在此代码中,读取也不会在遇到第一个 EOF 时终止。是否可以在第一次遇到时终止读取EOF。
  • 它确实以我的第一个 EOF 终止。您能否在问题中添加一个输入示例?
  • 对于您的解决方案中给出的相同示例输入,我必须提供两个 EOF 来终止扫描。但是,我正在使用代码块来编译代码。
  • 与您的问题无关,但我需要在写入文件的fprintf() 中添加一个换行符,因此更新了上面的代码。在最后一行输入之后,在按 Ctrl-Z 之前是否按 Enter 键?
  • 要添加,fscanf() 需要在一行上单独遇到EOF 才能按您的意愿运行。 You may want to have a look at this.
【解决方案2】:

fscanf() 返回成功读取的项目数。它不返回 EOF。检查这个:https://www.tutorialspoint.com/c_standard_library/c_function_fscanf.htm

【讨论】:

  • man fscanf: "如果在第一次成功转换或匹配失败之前到达输入结尾,则返回值 EOF。如果发生读取错误,也返回 EOF"
猜你喜欢
  • 2019-01-29
  • 2020-04-20
  • 2021-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多