【问题标题】:Confusing behavior with EOF and loops in C [duplicate]C中的EOF和循环令人困惑的行为[重复]
【发布时间】:2017-06-22 21:14:58
【问题描述】:

我正在编写一个从键盘读取未定义数量的整数的 C 程序。无限。该程序有一个循环,它使用 scanf 读取整数并存储要显示的最低和最高值。如果用户输入负数或非整数,则循环结束并显示信息(最小值和最大值)。

注意:我不想使用“ISDIGIT”或“FGET”等内置函数。不知道他们是什么,我不想“作弊”。

我发现我的 EOF 值为 -1。我尝试将“while(scanf("%d", &num) > -1)" 放入我的循环中。如果您输入一个字符(继续阅读并且永不结束循环),这将不起作用。如果您输入诸如“--2”之类的双重否定,它有时会中断循环。无论如何,它不起作用。

我的问题在于我的程序将我的当前代码 的行为混淆了。有时它不会保持或读取零。有时它只存储和显示第二高的值。有时在我输入字符或符号以触发循环结束后,它会显示倒数第二个最高或最低值。其他时候它工作得很好。如果最小值不等于 1 且小于 1,我尝试了一些更合乎逻辑的语句来强制最小值为零,但这也不起作用。

一个奇怪行为的例子......

输入一些整数值,EOF退出...

0

1

2

3

4

e

不是整数

最小值为0

最大值为3

谁能解释为什么会发生这种情况并提供解决方案和/或提示?我已经搜索了几个小时了。

谢谢!

这是我的代码...

int min;

int max;

int num;

printf(" Enter some integer values, EOF to quit...\n");
scanf("%d\n", &num);

min = max = num;

 while(scanf("%d", &num) == 1)
  {
    if(num > max)
     {
      max = num;
     }

    else if(num < min)
     {
      min = num;
     }
   scanf("%d\n", &num);

 }//while(scanf("%d", &num) == 1);


    printf(" not an int \n");


    printf(" The minimum value is %d\n", min);
    printf(" and the maximum value is %d\n", max);

【问题讨论】:

  • 您为每个循环调用了scanf 两次。这真的是你想要的吗?
  • 当您输入不能为整数的内容时,scanf() 返回 0,而不是 EOF。
  • "...来自键盘的未定义数量的整数。没有限制。"它是哪一个:未定义或无限?这两个术语在技术上是正交的;您不能将 undefined define 定义为 unlimited
  • 另外,你真的应该做更多的研究。这是一个常见的问题,并且已经有了答案! :(
  • 也许你应该阅读 scanf 的文档。这不是作弊

标签: c loops scanf


【解决方案1】:

您可以使用scanf 使这个“工作”,但它不会真正工作。 scanf is ill advised for a large number of reasons.

例如,假设我们这样做了:

printf("Enter some integers, or ctrl-D to quit.\n");
while(scanf("%d", &input) != EOF) {
    if(input > max) {
        max = input;
    }
    else if(input < min) {
        min = input;
    }
}

似乎很明智,scanf 如果没有任何输入,则返回 EOF。而且它似乎有效。

$ ./test
Enter some integers, or ctrl-D to quit.
230
-238 
5
max: 230, min: -238

但是如果我们给它一些不是数字的东西呢?

$ ./test
Enter some integers, or ctrl-D to quit.
230
-238
5
ldsfkj
^D
^D
^D
^C

为什么它不会停止?如果它无法读取所需内容,会将其留在标准输入缓冲区。它尝试读取ldsfkj,因为它不是整数而失败,返回0(不是EOF),因为它不匹配任何东西。但是ldsfkj 仍然在缓冲区中,所以当它再次循环时,它会再次读取它并再次失败。这是scanf的一大缺陷。

好的,如果我们检查它是否扫描了某些东西呢?

while(scanf("%d", &input) == 1) {
    ...
}

再次,似乎工作得很好......直到我们输入一个不是整数的东西。然后它就停止了,因为scanf 失败了。这不是我们想要的行为。

$ ./test
Enter some integers, or ctrl-D to quit.
2039
-203
23.4
max: 2039, min: -203

安全的做法是逐行读取输入并使用sscanf 处理它。这将读取该行与解析该行分开。我们不必担心事情会卡在缓冲区中,而且我们可以通过解析做更多事情,比如给用户一条错误消息。

printf("Enter some integers, or ctrl-D to quit.\n");
char line[256];
while(fgets(line, 256, stdin) != NULL) {
    if( sscanf(line, "%d", &input) != 1 ) {
        puts("Sorry, I don't understand that");
        continue;
    }

    if(input > max) {
        max = input;
    }

    if(input < min) {
        min = input;
    }
}

请注意,我们总是同时检查minmax,因为现在input 可能同时是两者。

请注意,我们使用fgets 而不是gets,因为gets 不会将其输入限制为字符串的大小,它很容易溢出其缓冲区。


第二部分是使最小/最大代码更简单。不要将第一个数字设为既是最小值又是最大值的特殊情况,而是将可能的最大整数分配给min,将可能的最小整数分配给max。然后保证第一个输入是最小值和最大值。这些限制可以在limits.h 中找到。

这一切都在一起了。

#include <stdio.h>
#include <limits.h>

int main() {
    int min = INT_MAX;
    int max = INT_MIN;
    int input;

    printf("Enter some integers, or ctrl-D to quit.\n");
    char line[256];
    while(fgets(line, 256, stdin) != NULL) {
        if( sscanf(line, "%d", &input) != 1 ) {
            puts("Sorry, I don't understand that");
            continue;
        }

        if(input > max) {
            max = input;
        }

        if(input < min) {
            min = input;
        }
    }

    printf("max: %d, min: %d\n", max, min);
}

该程序有一个小故障。我把它作为练习留给你找到并修复它。

【讨论】:

  • while( scanf("%d" ,&input ) == 0) 时会发生什么,你也可以添加这种情况吗?
  • @SurajJain scanf 返回匹配的项目数。 0 表示它不匹配任何东西,所以循环会直到它被赋予一个数字。除非第一个输入是匹配项,否则第一个不匹配项将保留在缓冲区中,并且循环它将无限循环该不匹配项。你可以自己试试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-07
  • 2011-11-09
  • 1970-01-01
相关资源
最近更新 更多