为什么scanf在无效输入上陷入无限循环?(复制)

时间:2023-02-12 08:46:09

This question already has an answer here:

这个问题已经有了答案:

In line 5 I read an integer and isint is getting 1 if it reads an integer or 0 if it's not an integer. If isint is 0 I have a loop asking user to give an integer and I read until the user gives an integer. I try this code giving a character instead of an integer but I have an infinite loop. The program just doesn't wait to give a new input. What's wrong with my code?

在第5行中,我读取一个整数,如果它读取一个整数或0,则isint得到1,如果它不是整数。如果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 个解决方案

#1


10  

As others have mentioned, if scanf can't parse the input, it leaves it unscanned.

正如其他人所提到的,如果scanf不能解析输入,它就不会扫描。

Generally scanf is a poor choice for interactive input because of this kind of behavior, and because it doesn't match the line-at-a-time interface experienced by the user.

通常,scanf对于交互式输入来说是一个糟糕的选择,因为这种行为,而且它与用户体验到的逐行界面不匹配。

You are better off reading one line into a buffer using fgets. Then parse that line using sscanf. If you don't like the input, throw the whole line away and read another one.

最好使用fgets将一行读入缓冲区。然后使用sscanf解析这一行。如果你不喜欢输入,把整行都丢掉,再读另一行。

Something like this:

是这样的:

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

(For production code you'll want to handle long lines, check return codes, also check for trailing garbage after the number, etc.)

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

Actually, an even better approach would be to not use scanf if you just want to read an integer, and instead use strtol. That gives you a handy pointer to the character just after the number, and you can check that it's whitespace or nul.

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

#2


4  

When scanf is confronted with a non-digit it will not consume any input and return that zero integers were read. The non-digit will stay in the input for the next call to scanf that will behave the same as the first call, etc.

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

In answer to your question below. You could use fgetc to parse at least one character, but this will give the error messages for every character already typed. Typically I think you want to skip until a newline. To this end you could use fgets as suggested by poolie. Or you could add the following after scanf.

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

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

P.S: In your case it is probably better to put it just before the first printf in the loop.

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

#1


10  

As others have mentioned, if scanf can't parse the input, it leaves it unscanned.

正如其他人所提到的,如果scanf不能解析输入,它就不会扫描。

Generally scanf is a poor choice for interactive input because of this kind of behavior, and because it doesn't match the line-at-a-time interface experienced by the user.

通常,scanf对于交互式输入来说是一个糟糕的选择,因为这种行为,而且它与用户体验到的逐行界面不匹配。

You are better off reading one line into a buffer using fgets. Then parse that line using sscanf. If you don't like the input, throw the whole line away and read another one.

最好使用fgets将一行读入缓冲区。然后使用sscanf解析这一行。如果你不喜欢输入,把整行都丢掉,再读另一行。

Something like this:

是这样的:

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

(For production code you'll want to handle long lines, check return codes, also check for trailing garbage after the number, etc.)

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

Actually, an even better approach would be to not use scanf if you just want to read an integer, and instead use strtol. That gives you a handy pointer to the character just after the number, and you can check that it's whitespace or nul.

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

#2


4  

When scanf is confronted with a non-digit it will not consume any input and return that zero integers were read. The non-digit will stay in the input for the next call to scanf that will behave the same as the first call, etc.

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

In answer to your question below. You could use fgetc to parse at least one character, but this will give the error messages for every character already typed. Typically I think you want to skip until a newline. To this end you could use fgets as suggested by poolie. Or you could add the following after scanf.

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

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

P.S: In your case it is probably better to put it just before the first printf in the loop.

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