使用EOF和C中的循环混淆行为

时间:2017-02-06 01:13:35

标签: c loops scanf

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

注意:我不想在“ISDIGIT”或“FGET”等功能中使用内置功能。不知道它们是什么,我不想“欺骗”。

我发现我的EOF值是-1。我尝试在我的循环中放入“while(scanf(”%d“,& num)> -1)”。如果你输入一个char(继续阅读并且永远不会结束循环),这就什么都不做。如果你输入一个双重负数如“ - 2”,它有时会打破循环。无论如何它都不起作用。

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

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

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

0

1

2

3

4

ë

不是int

最小值为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);

1 个答案:

答案 0 :(得分: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

为什么不停止?如果它无法读取所需内容, 将其保留在stdin缓冲区 。它尝试读取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现在可以同时使用。{/ p>

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

第二部分是使min / max代码更简单。不是将第一个数字作为min和max的特殊情况,而是将最大可能的整数分配给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);
}

该计划有一个小故障。我把它作为练习让你找到并修复它。