为什么scanf在无效输入上陷入无限循环?

时间:2013-06-02 11:54:01

标签: c scanf stdio

在第5行中,我读取一个整数,isint如果读取整数则为1,如果不是整数则为0。如果isint为0,我有一个循环要求用户给出一个整数,我会读取,直到用户给出一个整数。我尝试这个代码给出一个字符而不是一个整数,但我有一个无限循环。该程序只是不等待提供新的输入。我的代码出了什么问题?

#include <stdio.h>

int main(void) {

  int arg1;
  //int arg2;
  int attacknum = 1;
  int isint = 1;

  //printf("Insert argument attacks and press 0 when you have done this.\n");
  printf("Attack %d\n", attacknum);
  attacknum++;
  printf("Give attacking argument:");
  isint = scanf("%d", &arg1);  //line 5

  while(isint == 0){
    printf("You did not enter a number. Please enter an argument's number\n");
    isint = scanf("%d", &arg1);
    printf("is int is %d\n", isint);
  }
  return 0;
}

2 个答案:

答案 0 :(得分:11)

正如其他人所提到的,如果scanf无法解析输入,则会使其保持未扫描状态。

通常scanf因为这种行为而导致交互式输入的选择不佳,并且因为它与用户所经历的一次性界面不匹配。

最好使用fgets将一行读入缓冲区。然后使用sscanf解析该行。如果您不喜欢输入,请抛弃整条线并阅读另一条线。

这样的事情:

#include <stdio.h>

int main(void)
{
  char line[256];

  int arg1;
  int isint;

  while (1) {
    printf("Give attacking argument:");
    fgets(line, sizeof line, stdin);
    isint = sscanf(line, "%d",&arg1);
    if (isint) break;

    printf("You did not enter a number.Please enter an argument's number\n");
  }

  printf("Thanks for entering %d\n", arg1);

  return 0;
}

(对于生产代码,您需要处理长行,检查返回代码,还要检查数字后面的尾随垃圾等)。

实际上,如果您只想读取一个整数,而不是strtol,那么更好的方法是不使用scanf 。这样就可以在数字后面找到一个指向字符的方便指针,你可以检查它是空格还是空格。

答案 1 :(得分:4)

scanf遇到非数字时,它不会消耗任何输入并返回读取的零整数。非数字将保留在输入中,以便下一次调用scanf,其行为与第一次调用相同,等等。

回答下面的问题。您可以使用fgetc来解析至少一个字符,但这会为已键入的每个字符提供错误消息。通常我认为你想跳过换行符。为此,您可以使用poolie建议的fgets。或者您可以在scanf之后添加以下内容。

int ch;
if (isint == 0)
while ((ch = fgetc(stdin)) != EOF && ch != '\n')
{
     /* Skip characters */
}

P.S:在你的情况下,最好把它放在循环中的第一个printf之前。