【问题标题】:C: scanf did not stop in infinite while loop [duplicate]C:scanf没有在无限循环中停止[重复]
【发布时间】:2018-11-26 04:14:52
【问题描述】:

我想实现一个简单的代码来在输入类型不是整数时打印错误信息。

以下是示例代码。

int num;
while (1) {
    printf("Input the value of integer: ");
    int result = scanf(" %d", &num);
    if (result == 0) {
        printf("ERROR-Not an integer.\n");
    }
    else if (num < 0) {
         printf("ERROR- Not positive.\n");    
    }else{ 
        break;   
    }
}

在这段代码中,如果值不是整数,“scanf”会询问数字。

但是,当输入不是整数时,此函数没有中断。

也许问题在于缓冲区的值。 "fflush" 会是解决方案,但我不想使用它。

【问题讨论】:

  • 不需要" %d" 中的前导空白字符,因为%d 转换说明符已经使用前导空白字符;唯一使用前导空格的转换说明符是%c%n%[]
  • 测试应该是result != 1,因为在输入失败的情况下结果可能是否定的
  • 您可以从scanf() 获得 3 个结果 — 1、0、EOF。当你得到 0 时你报告了一个错误,但是你没有做任何事情来修复这个错误,所以下一次尝试也会失败,并且会一直失败,直到你对输入流中不需要的字符做一些事情。您还应该检测 EOF 并终止循环。通常,您应该将错误报告给标准错误 (stderr) 而不是标准输出 (stdout)。无论如何,这就是它的目的。

标签: c while-loop scanf


【解决方案1】:

问题是您在 匹配失败 的情况下未能清空-stdin。您正在寻找整数输入。如果用户输入的不是整数,则会发生匹配失败。当匹配失败发生时,从stdin提取字符停止并且导致匹配失败的字符留在输入缓冲区中(stdin这里)未读——如果你在没有先清除stdin的情况下尝试再次阅读,就等着再次咬你……如果你在循环中接受输入——好吧,你知道会发生什么……

(亲爱的...我尝试阅读 int 并失败了,我一直在尝试但一直失败 - 帮助??)

如何解决?

非常简单,您必须在匹配失败后清空stdin。你比大多数人做得更好——你正在检查返回,但你还有一个难题要添加——当匹配失败发生时,empty_stdin() 的一个简单函数。一种非常便携且非常简单的方法是简单地提取所有字符,直到遇到换行符或EOF,例如:

void empty_stdin(void) {
    int c = getchar();

    while (c != '\n' && c != EOF)
        c = getchar();
}

在您的示例中将所有部分放在一起,您可以这样做:

#include <stdio.h>

void empty_stdin(void) {
    int c = getchar();

    while (c != '\n' && c != EOF)
        c = getchar();
}

int main (void) {
    int num;
    while (1) {
        printf("Input the value of integer: ");

        int result = scanf(" %d", &num);

        if (result == EOF) {    /* handle ctrl+d (ctrl+z on win) */
            printf (" user canceled input (manual EOF)\n");
            break;
        }
        else if (result == 0) { /* matching failure */
            printf("ERROR-Not an integer.\n");
            empty_stdin();      /* remove offending characters */
        }
        else if (num < 0) {
            printf ("ERROR- Not positive.\n");    
        }
        else        /* positive number enetered */
            break;
    }

    return 0;
}

@David Bowling 已经在 cmets 中解释说," %d" 中的前导 space 是不必要的,因为所有数字转换都会消耗前导空格)

使用/输出示例

$ ./bin/scanf_empty
Input the value of integer: foo
ERROR-Not an integer.
Input the value of integer: -1
ERROR- Not positive.
Input the value of integer: bar
ERROR-Not an integer.
Input the value of integer: 1

测试手册EOF案例(用户按下Ctrl+d(或Ctrl+z窗口)

$ ./bin/scanf_empty
Input the value of integer:  user canceled input (manual EOF)

查看一下,如果您还有其他问题,请告诉我。

【讨论】:

    【解决方案2】:
    #include <stdio.h>
    
    int main()
    {
        int num;
        int result;
    
        while (printf("Please input an unsigned integer: "),
               (result = scanf(" %d", &num)) != 1 || num < 0 )
        {                                 //  ║          ╚══ was successful but negative
            if (result != 1) //  <════════════╝ 1 conversion was requested
                 fputs("ERROR: Not an integer.\n", stderr);  // write error messages
            else fputs("ERROR: Not positive.\n", stderr);   // to stderr
    
            int ch;  // the following loop *) reads garbage that might be left in stdin
            while ((ch = getchar()) != '\n' && ch != EOF);  // so the next scanf() won't
        }                                                   // fail because of it.
        printf("You entered: %d\n", num);
    }
    

    *) B 计划:

    scanf("%*[^\n]");  // this scanset matches all characters except newline
    getchar();        // remove the newline
    

    *) 计划-C:

    scanf("%*[^\n]");  // this scanset matches all characters except newline
    scanf("%*c");     // remove the newline
    

    示例对话框:

    Please input an unsigned integer: foo
    ERROR: Not an integer.
    Please input an unsigned integer: bar
    ERROR: Not an integer.
    Please input an unsigned integer: -75
    ERROR: Not positive.
    Please input an unsigned integer: 42
    You entered: 42
    

    【讨论】:

      【解决方案3】:

      您需要在每次 scanf 之前/之后清除标准输入。我个人更喜欢以前。

      fseek(stdin, 0, SEEK_END);

      int num;
      while (1) {
          fseek(stdin, 0, SEEK_END);
          printf("Input the value of integer: ");
          int result = scanf_s(" %d", &num);
          if (result == 0) {
              printf("ERROR-Not an integer.\n");
          }
          else if (num < 0) {
              printf("ERROR- Not positive.\n");
          }
          else {
              break;
          }
      }
      

      【讨论】:

      • 两种情况下的未定义行为。 fflush(stdin) 在标准中是明确的 UB,而 stdin 不保证是可搜索的。
      • stdin 只有在文件被重定向到 stdin 时才可搜索,例如./myprog &lt; myfile.
      • @DarkSorrow 看到其他答案了吗?
      猜你喜欢
      • 2017-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-21
      • 2015-02-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多