#include<stdio.h>
#include<ctype.h>
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);
}
该代码应该显示用户输入的所有整数的总和。但是,当用户输入一个字母作为输入时,它没有陷入错误,而是陷入了无限循环,打印了“输入数字”语句,但不在循环中运行任何其他语句。
有人可以告诉我为什么会这样吗?
答案 0 :(得分:2)
scanf
很奇怪。它具有内部缓冲区,并且仅在该缓冲区为空时才从流中读取。在代码的开头,没有任何内容,因此从标准输入中读取一行。然后scanf
尝试在那里找到一个整数。如果找到一个整数,它将报告已成功读取一项(通过返回1
)并将读取的值放入提供的指针位置。但是,如果找不到整数,则它将返回0
以表示“零项已成功读取”,并且它不会消耗缓冲区中的任何内容。这意味着,下次调用scanf
时,缓冲区将不会为空,因此不会再次提示用户输入新行,并且scanf
将再次尝试读取完全相同的整数将其放置在上次尝试的位置(并且会因完全相同的原因而失败)。因此,无限循环。
为说明这种“缓冲”情况,请尝试以下操作:
scanf("%d", &a);
scanf("%d", &b);
printf("a: %d, b: %d\n", a, b);
并在一行中输入12 53
,作为第一个scanf
的输入。神奇地,a
以12
结尾,而b
以53
结尾。魔术的解释是-第一个scanf
发现缓冲区为空,从用户那里读取行,并发现了一个整数,就像被告知的那样;第二个scanf
找到了缓冲区,那里还有一些东西,并继续读取最后一个中断的地方,而不必要求用户输入新行。
正如其他人已经评论过的那样,通常最好自己读一行(fgets
)并自己解析(strtol
),或者如果您绝对需要使用scanf
,请务必检查scanf
的返回码,以了解您的期望。有关scanf
失败的情况,如何清除输入缓冲区,请参见here。
答案 1 :(得分:0)
scanf()
不会丢弃与格式说明符不匹配的输入。您应该将其与%s
一起放在char []中阅读,然后执行atoi()
尝试将其转换为字符串。如果失败,ERRNO
将被设置为某些错误代码。这样,如果输入的不是数字,就不会留下任何未处理的输入。
答案 2 :(得分:0)
下面的代码段是对您的代码的正确修复。检查scanf()是否成功,然后继续
function Header()
{
$this->SetleftMargin(30);
$this->SetFont('Times', 'B', 14);
$this->Cell(0, 10, 'Office 1', 0, 0, 'C');
$this->Ln(20);
$this->headerTable(); // add this
}
function Footer()
{
$this->SetY(-15);
$this->SetFont('Times', '', 8);
$this->Cell(0, 10, 'Page ' . $this->PageNo() . '/{nb}', 0, 0, 'C');
$this->footerTable(); // add this
}
答案 3 :(得分:0)
一种可能的解决方案是在scanf之后添加输入缓冲区清除代码,例如用getchar循环:
#include<stdio.h>
#include<ctype.h>
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);
}
输入缓冲区清除的其他已知选项:
fseek(stdin,0,SEEK_END);
fflush(stdin);
(适用于某些编译器和操作系统)答案 4 :(得分:0)
这个问题已经here得到了回答。
引用答案:
%d转换说明符期望输入文本的格式为 十进制整数。如果不是,则转换失败并且字符 导致转换失败的原因留在输入流中。 使用%d转换说明符进一步调用scanf()会阻塞 在同一角色上。
这基本上意味着,当您使用scanf()
作为转换说明符来调用%d
时,它将期望用户输入一个十进制整数。但是,当用户输入字符(%c)作为输入时,转换失败,并且输入的字符保留在输入流中。这将导致while循环永远持续下去,而又不允许用户输入更多输入。
为防止这种情况,您可以尝试以下操作:
while (x != 0){
int tmp;
if (scanf("%d", &tmp) == 0)
getchar();
else
number = tmp;
}