输入一个字符作为整数变量的输入,给出一个无限循环

#include #include int main() { int number, sum = 0; // loop body is executed at least once do { printf("Enter a number: "); scanf("%d", &number); sum += number; } while(number != 0); printf("Sum = %d",sum); } 

该代码应该打印用户输入的所有整数的总和。 但是当用户输入一个字母作为输入时,它不会抛出错误,而是进入无限循环,打印“输入数字”语句但不在循环中运行任何其他语句。

有人能告诉我为什么会这样吗?

对代码的正确修复将是以下代码段。 检查scanf()是否成功,然后继续

 if (scanf("%d", &number) != 1) { break; } 

scanf很奇怪。 它有一个内部缓冲区,只有当缓冲区为空时才会从流中读取。 在代码的开头,什么都没有,所以从标准输入读取一行。 然后scanf尝试在那里找到一个整数。 如果找到一个整数,它将报告它成功读取一个项目(通过返回1 )并将读取值放入提供的指针位置。 但是,如果未找到整数,则“零项成功读取”将返回0 ,并且不会从缓冲区中消耗任何内容 。 这意味着,下次调用scanf ,缓冲区不会为空,因此不会再次提示用户输入新行, scanf将再次尝试读取与上次尝试完全相同的整数(并且失败的原因完全相同)。 因此,无限循环。

为了说明这个“缓冲”的事情,试试这个:

 scanf("%d", &a); scanf("%d", &b); printf("a: %d, b: %d\n", a, b); 

在一行中输入12 53 ,作为第一个scanf的输入。 可悲的是, a最终为12b最终为53 。 神奇的解释是 – 第一个scanf发现缓冲区为空,从用户读取行,并找到一个整数,因为它被告知; 第二个scanf发现缓冲区中仍然存在一些东西,并继续读取它最后离开的位置,而不必询问用户是否有新行。

正如其他人已经评论过的那样,通常最好自己阅读一行( fgets )并自己解析( strtol ),或者如果你绝对需要使用scanf ,请务必检查scanf是否通过检查它的返回值来读取你预期的内容码。 如果scanf失败,请参见此处有关如何清除输入缓冲区的信息。

scanf()不会丢弃与格式说明符不匹配的输入。 您应该在带有%s的char []中读取它,然后执行atoi()以尝试将其转换为字符串。 如果失败, ERRNO将被设置为一些错误代码。 这样,如果输入的数字不是数字,您将不会留下任何未处理的输入。

这个问题已在这里得到解答。

引用答案:

%d转换说明符期望输入文本格式化为十进制整数。 如果不是,则转换失败,导致转换失败的字符将保留在输入流中。 使用%d转换说明符进一步调用scanf()将阻塞相同的字符。

这基本上意味着当您使用%d作为转换说明符调用scanf()时,它会期望用户输入十进制整数。 但是,当用户输入字符(%c)作为输入时,转换失败并且输入的字符保留在输入流中。 这将导致while循环永远继续,而不允许用户输入任何更多输入。

为了防止这种情况,您可以尝试以下方法:

 while (x != 0){ int tmp; if (scanf("%d", &tmp) == 0) getchar(); else number = tmp; } 

其中一种可能的解决方案是在scanf之后添加输入缓冲区清理代码,例如使用getchar循环:

 #include #include int main() { int number = -1; // any number not equal 0, to prevent loop break // after wrong input at the first iteration int sum = 0; int c; // char to read input // loop body is executed at least once do { printf("Enter a number: "); if(scanf("%d", &number) == 1) { sum += number; // add if read was successful } // buffer clean while ((c = getchar()) != '\n' && c != EOF); } while(number != 0); printf("Sum = %d",sum); } 

输入缓冲区清理的已知选项:

  1. fseek(stdin,0,SEEK_END);
  2. fflush(stdin); (对于某些编译器和操作系统,它可以工作)