输入一个字符作为整数变量的输入,从而产生无限循环

时间:2018-08-07 04:41:04

标签: c

#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);

}

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

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

5 个答案:

答案 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的输入。神奇地,a12结尾,而b53结尾。魔术的解释是-第一个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);
}

输入缓冲区清除的其他已知选项:

  1. fseek(stdin,0,SEEK_END);
  2. 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;
}