scanf失败了为什么?

Abo*_*our 2 c scanf


当我写这篇文章时,编译并运行:

int x;   
scanf ("%d", &x);  
while (x!=4) {  
    scanf ("%d", &x);  
}
Run Code Online (Sandbox Code Playgroud)

当插入char或小于4的double数时,它进入一个无限循环.
当插入大于4的double时,它会终止.
任何解释?

Joh*_*ode 11

C语言标准(n1256):

7.19.6.2 The fscanf function
...
4 The fscanf function executes each directive of the format in turn. If a directive fails, as detailed below, the function returns. Failures are described as input failures (due to the occurrence of an encoding error or the unavailability of input characters), or matching failures (due to inappropriate input).
...
7 A directive that is a conversion specification defines a set of matching input sequences, as described below for each specifier. A conversion specification is executed in the following steps:

8 Input white-space characters (as specified by the isspace function) are skipped, unless the specification includes a [, c, or n specifier.250)

9除非规范包含n说明符,否则从流中读取输入项.输入项被定义为输入字符的最长序列,其不超过任何指定的字段宽度,并且是匹配的输入序列的前缀,或者是匹配的输入序列的前缀.251)输入项目保持未读后的第一个字符(如果有).如果输入项的长度为零,则指令的执行失败; 除非文件结束,编码错误或读取错误阻止了流的输入,否则此条件是匹配失败,在这种情况下,它是输入失败.

10除了%说明符的情况外,输入项目(或者,在%n的情况下)指令,输入字符数)转换为适合转换说明符的类型.如果输入项不是匹配序列,则指令的执行失败:此条件是匹配失败.除非通过*指示赋值抑制,否则转换的结果将放在由尚未收到转换结果的format参数后面的第一个参数指向的对象中.如果此对象没有适当的类型,或者无法在对象中表示转换结果,则行为未定义.

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

scanf()返回成功作业的数量; 您需要检查此结果以查看转换是否成功,如下所示:

int x = 0;
while (x != 4)
{
  int result = scanf("%d", &x);
  if (result != 1)
  {
    printf("Last call to scanf() failed; exiting\n");
    break;
  }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,您仍然在输入流中卡住了错误的输入.有许多策略可以解决这个问题.你可以删除有问题的角色,getchar然后再试一次:

while (x != 4)
{
  int tmp;
  if (scanf("%d", &tmp) == 0)
    getchar();
  else
    x = tmp;
}
Run Code Online (Sandbox Code Playgroud)

或者您可以尝试阅读下一个换行符,假设所有剩余的输入都是b0rked:

while (x != 4)
{
  int tmp;
  if (scanf("%d", &tmp) == 0)
    while (getchar() != '\n')
      ;
  else
    x = tmp;
}
Run Code Online (Sandbox Code Playgroud)

或者您可以尝试将输入作为文本读取并使用strtol()(我的首选技术)转换为整数:

char input[SOME_SIZE];
int x = 0;
...
while (x != 4)
{
  if (fgets(input, sizeof input, stdin))
  {
    char *check;
    int tmp = (int) strtol(input, &check, 10);
    if (!isspace(*check) && *check != 0)
    {
      printf("%s is not a valid integer: try again\n", input);
    }
    else
    {
      x = tmp;
    }
  }
  else
  {
    printf("Read error on standard input\n");
    break;
  }
}
Run Code Online (Sandbox Code Playgroud)

这是更多的工作,但它允许您在分配之前捕获错误的输入x.


Let*_*_Be 6

你不检查scanf实际是否成功,因此你会遇到错误.对于每个循环,scanf将尝试读取和失败.

scanf 返回成功读取的项目数,因此将循环修改为这样的东西 while (x!=4) { if (scanf("%d",&x) != 1) break; }


pmg*_*pmg 5

当scanf停止在输入流中的特定位置扫描时,它将永远不会前进流,因此下一个scanf将再次尝试相同的错误......并再次......再次

input: 42 23 foo ...
scanf: ^
x      42
scanf:   ^
x      23
scanf:      ^
x      unusable
scanf:       ^
x      unusable
scanf:       ^
x      unusable
scanf:       ^
x      unusable
scanf:       ^
x      unusable

  • @Aboelnour如果你输入`4.29419541951`它将把'4`作为整数读出并退出.如果输入`3.29419541951`,它将读取`3`然后在下一个循环失败,因为第一个字符是`.`.您需要检查返回值.检查我的答案中的代码. (2认同)