while 循环中的 scanf 仅在第一次迭代时读取

scanf in a while loop reads on first iteration only

注意:请注意这不是 Why is scanf() causing infinite loop in this code? 的副本,我已经看过那个问题,但问题在于他检查的是 ==0 而不是 !=EOF。还有,他的问题不一样,那里的"infinite loop"还在等待用户输入,就是不退出。

我有以下 while 循环:

while ((read = scanf(" (%d,%d)\n", &src, &dst)) != EOF) {
                if(read != 2 ||
                         src >= N || src < 0 ||
                         dst >= N || dst < 0) {
                        printf("invalid input, should be (N,N)");
                } else
                        matrix[src][dst] = 1;
        }

其目的是读取格式为(int,int)的输入,读取到EOF时停止读取,如果收到无效输入则重试。

问题是,scanf只对第一次迭代有效,之后就是死循环。该程序不等待用户输入,它只是一直假设上次输入相同。

readsrcdst 属于 int.

类型

我看过类似的问题,但他们似乎没有检查 scanf returns 0 而不是检查 EOF,答案告诉他们切换到 EOF .

scanf 提示用户进行一些输入。假设用户按照预期的方式进行操作,他们将键入一些数字,然后按下回车键。

数字将存储在输入缓冲区中,但换行符也会存储在输入缓冲区中,换行符是在他们按下回车键时添加的。

scanf 将解析数字以生成一个整数,并将其存储在 src 变量中。它在换行符处停止,该换行符保留在输入缓冲区中。

稍后,第二个 scanf 在输入缓冲区中查找换行符。它会立即找到一个,因此不需要提示用户进行更多输入。

你需要使用

int c;
while((c=getchar()) != '\n' && c != EOF);

while 循环的末尾,以便 clear/flush 标准输入流 (stdin)。为什么?答案见下:

您拥有的格式字符串 (" (%d,%d)\n") 的 scanf 需要用户键入

  1. 左括号(()
  2. 一个数(为第一个%d)
  3. 一个逗号(,)
  4. 一个数字(最后一个%d)

space(你的scanf格式字符串的第一个字符)和换行符(\n,它是你的[=13格式字符串的最后一个字符=]) 被认为是 whitespace characters。让我们看看 C11 标准对 fscanf 的格式字符串中的白色 space 字符有什么看法(是的。我说 fscanf 是因为它等同于 scanf 当第一个参数是 stdin):

7.21.6.2 The fscanf function

[...]

  1. A directive composed of white-space character(s) is executed by reading input up to the first non-white-space character (which remains unread), or until no more characters can be read. The directive never fails

因此,所有白色space 字符 skips/discards 所有白色space 字符,如果有的话,直到第一个非白色space 字符,如上面的引述所示.这意味着 scanf 格式字符串开头的 space 会清除所有前导白色 space 直到第一个非白色 space 字符和 \n 角色也一样。

当您按照 scanf 中的格式字符串输入正确的数据时,scanf 的执行不会结束。这是因为 \n 没有在 stdin 中找到非白色 space 字符,只有在找到一个时才会停止扫描。所以,你必须删除它。

下一个问题是当用户键入不符合 scanf 格式字符串的其他内容时。发生这种情况时,scanf 失败并且 returns。导致 scanf 失败的其余数据在 stdin 中占优势。下次调用时,scanf 会看到此字符。这也会使 scanf 失败。这会导致无限循环。

要修复它,您必须使用上面显示的方法在 while 循环的每次迭代中清理/clear/flush stdin