在C语言中检测EOF

31

我正在使用以下的 C 代码从用户处获取输入,直到出现 EOF,但问题是这个代码没有运行,它在获取第一个输入后就终止了。这个代码有什么问题?

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

4
请注意:假设用户输入未被管道传递,检查EOF可能并不理想,因为我记得通常这意味着用户必须按ctrl+D退出,这是不明显的。 - Brian
6个回答

53

EOF只是一个带有值的宏(通常为-1)。您需要对某些内容进行测试,例如getchar()调用的结果。

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

if (feof(stdin))

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

在您的示例中,您应该检查scanf的返回值,如果指示未读取任何字段,则检查文件结尾。


3
注意Brian的评论:stdin通常不会注册EOF,因为用户总是可以输入更多内容。在类Unix系统中,这通常意味着按下control-D键。 - David Thornley
这取决于你所说的“通常”。如果你已经重定向了stdin(文件或管道,Unix或Windows),EOF通常会被正确地标记。在交互式Unix终端中,^D通常有效,在Windows文本模式下,在一行的开头使用^Z也可以。 - CB Bailey
你怎么知道它在哪里失败了?比如我让它读取4个字节,但是在读到2个字节时遇到了EOF,它会如何告诉我请求只被部分满足了呢? - MarcusJ

9
"EOF" 是 C 语言中的一个常量。你没有检查实际文件是否已到达文件结束标志。你需要像这样做:
while(!feof(stdin))

这是关于 feof 的文档。您还可以检查 scanf 的返回值。它返回成功转换的项目数,或者如果到达文件结尾,则返回 EOF

FILE函数中是否包含一个比使用EOF更好的测试变量?似乎检查实际文件指针上的状态比使用一些只有一半时间有效的奇怪函数更好。 - MarcusJ

4
另一个问题是你只使用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()进行解析。

-1

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

while(!EOF)

使用

while(!feof(stdin))

-1

您想检查scanf()的结果,以确保成功转换;如果没有成功,则有三种可能:

  1. scanf()无法处理不适用于%f转换说明符的字符(即,不是数字、点、'e'或'E');
  2. scanf()检测到EOF;
  3. scanf()在读取stdin时检测到错误。

示例:

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);
    }
 }

1
可能会出现无限循环清除行尾的情况。我建议使用“while (((ch = getchar()) != EOF) && (ch != '\n')) /* void */;”然后再次检查EOF并设置“moredata = 0;”。 - pmg
请开一个新问题。 - andig

-1
while(scanf("%d %d",a,b)!=EOF)
{

//do .....
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接