【问题标题】:Why doesn't scanf() wait for the next input if I previously entered a certain input如果我之前输入了某个输入,为什么 scanf() 不等待下一个输入
【发布时间】:2014-10-19 12:21:58
【问题描述】:

下面是我输入数字并打印的简单代码。它在 while(1) 循环内,所以我需要“输入无限次的数字 - 每次它都会打印数字并再次等待输入”。

#include<stdio.h>
int main()
{
    int i;

    while(1){
        printf("\nenter i \n");
        scanf("%d", &i);
        if(i==1)
        {
            printf("%d \n", i);
        }
    }
    return 0;
}

它工作正常。但突然我注意到如果我输入一个字符(例如:“w”)而不是数字,从那里它不会要求输入!!!** 它继续打印,

enter i
1
enter i
1
......

当我使用 GDB 进行调试时,我注意到在输入 "w" 后,字符 "w" 的值并没有存储在 &i 中。在我输入“w”之前,它有 0x00000001,以便在整个过程中打印“1”。

  1. 为什么它不要求另一个输入?据我所知,当我输入“w”时,“w”的 ascii 值应该存储在 &i 中。但它不会发生。

  2. 如果我把“int i;”放在while 循环内,它可以正常工作!为什么?

请按以下方式测试我的代码:

  • 复制粘贴并运行它
  • 当出现“输入 i”提示时,输入 1
  • 第二次输入“w”。看看会发生什么……

【问题讨论】:

  • 因为输入流中已经存在的虚假输入(您的w)尚未删除
  • scanf 不会消耗它不匹配的东西。您必须自己食用。
  • 那么,基本上,你想说scanf在你第一次输入w之后不再等待输入?
  • %d 是一个数字,对吧?
  • @mr-cracker 是什么让您认为阅读 w%d 会导致 w 的 ASCII 值?

标签: c while-loop scanf infinite-loop


【解决方案1】:

scanf%d 格式说明符将读取“看起来像数字”的所有内容,即满足严格定义的整数十进制表示格式的内容:一些可选空格后跟可选符号,后跟序列位数。一旦遇到不可能是十进制表示形式的字符,scanf 就会停止读取并保持输入流中的其余输入数据保持不变(等待下一个scanf)。如果您只输入w,您的scanf 将找不到任何“看起来像数字”的内容。它什么也不会读。相反,它将通过其返回值报告失败。同时您的w 将保留在输入流中,未读。下次您尝试scanf 时,完全相同的事情将再次发生。一次又一次,一次又一次...... w 将永远位于输入流中,导致您的每个 scanf 调用立即失败并且您的循环永远运行(除非您的未初始化变量 i 纯机会碰巧以 1 的值开始它的生命)。

您假设输入w 应该使scanf 读取w 的ASCII 码是完全错误的。这听起来与%c 格式说明符的作用很接近,但这甚至与%d 格式说明符的作用相去甚远。 %d 不会将任意字符读取为 ASCII 码。

还请注意,每次您尝试使用位于输入流中的w 调用scanf 时,您的scanf 都会失败并保留i 的值不变。如果您在循环内声明您的i,则i 的值在每次scanf 尝试失败后将保持未初始化和不可预测的状态。在这种情况下,您的程序的行为是未定义的。它甚至可能会产生一种“工作正常”的错觉(在这种情况下你可能会理解)。

【讨论】:

  • scanf成功后有没有办法清除inpustream?
【解决方案2】:

您还需要检查scanf 的返回值,因为它会返回成功扫描和解析的值的数量。如果它返回零(或EOF),那么您应该退出循环。

当您输入时会发生什么,例如字符'w' 而不是数字是scanf 函数将在扫描和解析时失败,并返回零。但是输入不会从输入缓冲区中删除(因为它没有被读取),所以在下一个循环中scanf 将再次读取非数字输入并失败,并且它将无限执行此操作。

【讨论】:

  • +1 为什么投反对票?这是第一个正确答案。
  • @Groo 我已经编辑了答案,在答案完成之前我得到了下注。
  • @Joachim:这很奇怪,我很确定在我投票后分数会降低(这就是我首先检查比率的原因)。可能已经有人反对了。
  • 这个答案应该被接受,因为它是最好的,也是第一个回答问题的人!
  • 我也想成为神,但我不是神。为什么要赞成这个答案并反对这个问题?告诉我,有什么区别?
【解决方案3】:

你可以试试这个解决方法:

int main()
{
    int i;
    char c;
    while (1)
    {
        printf("enter i: ");
        if (scanf("%d",&i) == 0)
            scanf("%c",&c); // catch an erroneous input
        else
            printf("%d\n",i);
    }
    return 0;
}

顺便说一句,你打算什么时候 break 退出那个(目前是无限的)循环?

【讨论】:

  • 当我尝试另一个程序时,我看到了这个错误,所以只是以简单的方式尝试。而已。无论如何谢谢
【解决方案4】:

您需要read up on scanf(),因为您的程序似乎基于一些错误的假设。

它不会解析字符,因为转换格式说明符%d 表示“十进制整数”。

另外,请注意,您必须检查返回值,因为 I/O 可能会失败。当您输入的内容与转换说明符不匹配时,scanf() 无法解析它。

你可能会更好地使用fgets()阅读整行,然后使用例如sscanf() 解析该行。这样更容易获得强大的输入读取。

【讨论】:

    【解决方案5】:

    scanf 可以检查返回类型,并基于该输入可以使用getchar 来解决您的问题。

    示例代码

        int main()
        {
            int i;
            int ch;
            while(1){
    
            printf("\nenter i \n");
            if (  scanf("%d", &i) !=1  )
            {
                /*consume the non-numeric characters*/
                for (; (ch = getchar()) != EOF && ch != '\n'; ) { }
            }
    
            if(i==1)
            {
                printf("%d \n", i);
            }
            }
            return 0;
        }
    

    说明:

    当 scanf("%d", &i) 遇到字符时,它不会读取它。该字符仍将保留在输入流中。所以要消耗这些字符,可以使用getchar()。然后scanf 将在进一步迭代中等待下一个输入。

    【讨论】:

      猜你喜欢
      • 2015-04-12
      • 1970-01-01
      • 2013-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-15
      • 2015-05-15
      • 1970-01-01
      相关资源
      最近更新 更多