【问题标题】:scanf in a while loop reads on first iteration onlywhile 循环中的 scanf 仅在第一次迭代时读取
【发布时间】:2023-04-07 18:02:01
【问题描述】:

注意:请注意这不是 Why is scanf() causing infinite loop in this code? 的重复项,我已经看到了这个问题,但问题是他检查的是 ==0 而不是 !=EOF。另外,他的问题不同,那里的“无限循环”还在等待用户输入,只是没有退出。

我有以下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 是否返回 0 而不是检查EOF,并且答案告诉他们切换到EOF

【问题讨论】:

  • scanf中删除\n
  • @user3121023 ,不好,输入无效后会停止接收输入。
  • @CoolGuy 我实际上是在没有\n 的情况下开始的,遇到了同样的问题。我添加它是因为我从另一个问题中看到了对它的推荐。对于您的第二个问题,任何输入 - 有效或无效 - 都会复制问题。
  • @Tom ,在if 的正文中尝试int c;while((c=getchar())!='\n' &amp;&amp; c!=EOF);
  • @Tom ,只需在 printf("invalid input, should be (N,N)"); 之后添加 int c;while((c=getchar())!='\n' &amp;&amp; c!=EOF);

标签: c scanf


【解决方案1】:

你需要使用

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

while 循环的末尾,以清除/刷新标准输入流(stdin)。为什么?答案如下:

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

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

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

7.21.6.2 fscanf 函数

[...]

  1. 由空白字符组成的指令通过读取输入直到第一个非空白字符(仍然未读取)或直到无法读取更多字符来执行。该指令永远不会失败

因此,所有空白字符都会跳过/丢弃所有空白字符(如果有),直到上面引用中看到的第一个非空白字符。这意味着scanf 格式字符串开头的空格会清除所有前导空格,直到第一个非空格字符和\n 字符相同。

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

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

要修复它,您必须使用上述方法在while 循环的每次迭代中清理/清除/刷新stdin

【讨论】:

    【解决方案2】:

    scanf 提示用户输入一些内容。假设用户做了他们期望的事情,他们会输入一些数字,然后按回车键。

    数字将存储在输入缓冲区中,但换行符也将存储在输入缓冲区中,这是由于它们按回车键而添加的。

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

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

    【讨论】:

    • 这并不能真正解决我的问题。你有什么可以解决它的建议吗?
    • 可以分享一下整个代码吗,(%d ,%d )后面加个空格可能有帮助,但需要验证
    • @yanivx , %d not 读取 \n。它跳过它。并且“假设用户按照他们的期望进行操作,他们会输入一些数字,然后按回车键。”是错误的。 OP 问题中的scanf 有括号和逗号。这些也需要输入
    • @CoolGuy 同意,但连续 2 个 scanfgetline 会导致这个问题,其中换行符满足第二个 scanf 的要求,我将尝试代码并返回
    • @Tom 这里是你的答案?您可以使用%s 来解决我在回答中提到的问题。这里有一个示例修复stackoverflow.com/a/5453684/2959769
    猜你喜欢
    • 1970-01-01
    • 2016-06-19
    • 1970-01-01
    • 2015-10-20
    • 2015-09-20
    • 2020-05-17
    • 2018-05-14
    • 2015-09-04
    • 1970-01-01
    相关资源
    最近更新 更多