【问题标题】:Detecting EOF in C在 C 中检测 EOF
【发布时间】:2010-11-28 13:44:14
【问题描述】:

我正在使用以下 C 代码从用户那里获取输入,直到 EOF 发生,但问题是这段代码不起作用,它在获取第一个输入后终止。谁能告诉我这段代码有什么问题。提前致谢。

float input;

printf("Input No: ");
scanf("%f", &input);

while(!EOF)
{
    printf("Output: %f", input);
    printf("Input No: ");
    scanf("%f", &input);
}

【问题讨论】:

  • 注意:假设用户输入不是管道,检查 EOF 可能并不理想,因为 IIRC 通常这意味着用户必须按 ctrl+D 退出,这是不明显的

标签: c stdio


【解决方案1】:

EOF 只是一个带有值(通常为 -1)的宏。您必须针对EOF 进行测试,例如getchar() 调用的结果。

测试流结束的一种方法是使用feof 函数。

if (feof(stdin))

请注意,“流结束”状态只会在读取失败后设置。

在您的示例中,您可能应该检查 scanf 的返回值,如果这表明没有读取任何字段,则检查文件结尾。

【讨论】:

  • 请注意 Brian 的评论:标准输入通常不会注册 EOF,因为用户总是可以输入更多内容。在 Unixy 系统上,这通常意味着 control-D。
  • 这取决于我的“通常”是什么意思。如果您已重定向标准输入(文件或管道、unix 或 Windows),通常会正确发出 EOF 信号。在交互式 unix 终端中,^D 通常有效,在 windows 文本模式下,行首的 ^Z 有效。
  • 你怎么知道它在哪里失败了?比如如果我要求它读取 4 个字节,并且它在 2 个字节处遇到 EOF,它将如何告诉我请求已部分满足?
【解决方案2】:

EOF 是 C 中的常量。您没有检查 EOF 的实际文件。你需要做这样的事情

while(!feof(stdin))

这是feof 的文档。也可以查看scanf的返回值。它返回成功转换的项目数,如果到达文件末尾,则返回 EOF

【讨论】:

  • FILE 函数是否包含一个比使用 EOF 更好测试的变量?似乎最好检查实际文件指针的状态,而不是使用一些只工作一半的奇怪函数。
【解决方案3】:

另一个问题是您只使用scanf("%f", &input); 阅读。如果用户键入了一些不能被解释为 C 浮点数的东西,比如“pi”,scanf() 调用不会将任何东西分配给input,并且不会从那里继续。这意味着它将尝试继续读取“pi”并失败。

考虑到其他张贴者正确推荐的对while(!feof(stdin)) 的更改,如果您在其中键入“pi”,则会出现无限循环打印出input 的前一个值并打印提示,但程序永远不会处理任何新的输入。

scanf() 返回它对输入变量的赋值数。如果它没有赋值,这意味着它没有找到浮点数,你应该阅读更多的输入,比如char string[100];scanf("%99s", string);。这将从输入流中删除下一个字符串(最多 99 个字符 - 额外的 char 用于字符串上的空终止符)。

你知道,这让我想起了我讨厌 scanf() 的所有原因,以及为什么我使用 fgets() 代替然后可能使用 sscanf() 解析它。

【讨论】:

    【解决方案4】:

    作为起点,您可以尝试替换

    while(!EOF)
    

    while(!feof(stdin))
    

    【讨论】:

      【解决方案5】:

      您想检查 scanf() 的结果以确保转换成功;如果没有,那么以下三件事之一是正确的:

      1. scanf() 被一个对于 %f 转换说明符无效的字符(即不是数字、点、'e' 或 'E')阻塞;
      2. scanf() 已检测到 EOF;
      3. scanf() 在读取标准输入时检测到错误。

      例子:

      int moreData = 1;
      ...
      printf("Input no: ");
      fflush(stdout);
      /**
       * Loop while moreData is true
       */
      while (moreData)
      {
        errno = 0;
        int itemsRead = scanf("%f", &input);
        if (itemsRead == 1)
        {
          printf("Output: %f\n", input);
          printf("Input no: ");
          fflush(stdout);
        }
        else
        {
          if (feof(stdin))
          {
            printf("Hit EOF on stdin; exiting\n");
            moreData = 0;
          }
          else if (ferror(stdin))
          {
            /**
             * I *think* scanf() sets errno; if not, replace
             * the line below with a regular printf() and
             * a generic "read error" message.
             */
            perror("error during read");
            moreData = 0;
          }
          else
          {
            printf("Bad character stuck in input stream; clearing to end of line\n");
            while (getchar() != '\n')
              ; /* empty loop */
            printf("Input no: ");
            fflush(stdout);
          }
       }
      

      【讨论】:

      • 清除到行尾时可能出现无限循环。我建议while (((ch = getchar()) != EOF) && (ch != '\n')) /* void */; 广告然后检查(再次)EOF 并设置moredata = 0;
      • 请打开一个新问题。
      【解决方案6】:
      while(scanf("%d %d",a,b)!=EOF)
      {
      
      //do .....
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-02-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-23
        • 2012-03-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多