【问题标题】:Scanf and loopsScanf 和循环
【发布时间】:2010-10-04 04:15:00
【问题描述】:

这是一段代码,它应该一遍又一遍地循环,直到用户输入一个介于 0 和 15 之间的数字

        int input;

        do
        {

                printf("Enter a number => ");
                scanf("%d",&input);
                printf("\n %d \n",input);

        }
        while (!(input>0 && input <15));

但是,如果用户输入“gfggdf”之类的内容,则会导致循环一遍又一遍地重复,并且永远不会再次提示用户输入......控制台看起来像这样

Enter a number =>
0
Enter a number =>
0
Enter a number =>
0
Enter a number =>
0
Enter a number =>
0
Enter a number =>
0
(looping indefinitely)

看完这本书后,似乎我需要做这样的事情来防止这种情况发生。

int input, error, status;
char skip_ch;

do
{
        error = 0;

        printf("Enter a number => ");
        status = scanf("%d",&input);
        printf("\n %d \n",input);

        if(status!=1)
        {
                error=1;
        }
        else if(input < 0 || input >15){
                error = 1;
        }

        do
        {
                scanf("%c",&skip_ch);
        }while(skip_ch != '\n');
}
while (error);

我了解需要检查 scanf 状态以确保它是有效输入,我不了解内部 do-while 循环。我觉得这本书从来没有真正向我解释过为什么需要像这样多次调用 scanf ,就像 scanf 缓冲区以某种方式被一堆垃圾填满了,它以某种方式通过循环一百万次来清理它你。

谁能给我解释一下这个黑魔法?

【问题讨论】:

  • 这本书的正确率是 25%。 始终检查输入函数的返回值。如果存在读取错误(坏扇区、媒体已删除……)或文件在 '\n' 之前结束,则最后一个 scanf 可能会进入无限循环

标签: c scanf


【解决方案1】:

这就是为什么有这么多类似问题的答案建议不要使用scanf()。

此外,您应该检查来自 scanf() 的返回值,因为它会告诉您何时出现问题 - 并且无法转换任何值。

通常推荐的解决方案是结合使用fgets() 读取输入行和sscanf() 在读取行后对其进行解析。

您的示例中的第二个循环围绕读取字符直到并包括换行符,从而重新同步 scanf() 并跳过任何虚假数据。这是一种冗长的做法;改用getchar() 会更简单:

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

注意“int c;”的使用——该类型不是“char”或“unsigned char”,因为它必须存储所有可能的char值加上EOF。

【讨论】:

    【解决方案2】:

    原始代码无限循环,因为当 scanf 无法将其转换为整数时,无效数据(“gfggdf”)没有从输入缓冲区中删除 - 它留在输入缓冲区中,所以下一次对 scanf 的调用会查看相同的数据,并且(当然)仍然无法将其转换为整数,所以循环再次执行,结果仍然没有改变。

    :

    do {
            scanf("%c",&skip_ch);
    }while(skip_ch != '\n');
    

    一次只读取一个字符(并忽略它),直到它到达行尾。如果您希望在没有循环的情况下摆脱输入缓冲区中的垃圾,您可以使用类似:scanf("%*[^\n]");

    另一种(可能更多)广泛使用的可能性是从读取整行开始,然后尝试转换行中的内容。无论是否转换,您已经将所有数据读取到行尾,因此下一次读取/转换尝试将从下一行开始,无论转换是否有效。这确实有一个潜在的弱点:如果您有一个非常长 行的输入,您最终可能会读取和存储大量您没有真正用处的数据。这很少有什么大不了的,但你仍然应该意识到这一点。

    【讨论】:

      【解决方案3】:

      首先,避免使用scanf(),改用fgets()。

      评估您的状况(第一个代码)。 0 &gt; 0 是 false。 0 &lt; 15 是 true。 false &amp;&amp; true 是 false。 !false 是 true。这就是它无限循环的原因。

      【讨论】:

      • 是的,我期待它循环,因为输入字符会导致输入 ==0,意想不到的部分是它不允许用户尝试输入其他内容,它而是进入了无限循环(我可能应该澄清这一点)。 Jerry Coffin 向我解释了发生了什么,之前的输入卡在 scanf 缓冲区中,因为 scanf 的“状态”设置为 0 表示错误,并且它没有清除缓冲区(因为错误)
      猜你喜欢
      • 2017-07-06
      • 2015-01-30
      • 1970-01-01
      • 1970-01-01
      • 2020-02-16
      • 2012-04-09
      • 1970-01-01
      • 2016-10-08
      • 2016-05-18
      相关资源
      最近更新 更多