代码之家  ›  专栏  ›  技术社区  ›  Kiran Shahi Jonny

为什么在C编程中scanf(“%d”,&number)将“a”作为29?

  •  0
  • Kiran Shahi Jonny  · 技术社区  · 7 年前

    我有以下C代码

    #include <stdio.h>
    int main()
    {
        int number;
    
        // printf() displays the formatted output
        printf("Enter an integer: ");
    
        // scanf() reads the formatted input and stores them
        scanf("%d", &number);
    
        // printf() displays the formatted output
        printf("You entered: %d", number);
        return 0;
    }
    

    这里我需要输入一个数字,但我输入了一个字符“a”,结果是29。我原以为它会引发异常,但我对输出感到惊讶。 Screen shots of an output of the program.

    4 回复  |  直到 7 年前
        1
  •  3
  •   Vlad from Moscow    7 年前

    对于启动器,无参数的主功能应声明如下

    int main( void )
    

    只需按以下方式更改程序

    #include <stdio.h>
    
    int main( void )
    {
        int number;
    
        // printf() displays the formatted output
        printf("Enter an integer: ");
    
        // scanf() reads the formatted input and stores them
        if (scanf("%d", &number) == 1)
        {
            // printf() displays the formatted output
            printf("You entered: %d\n", number);
        }
        else
        {
            puts("Invalid input");
        }
    
        return 0;
    }
    

    然后看看如果你尝试输入角色会发生什么 'a' 而不是数字。

    根据C标准中的功能描述(7.21.6.2 fscanf功能)

    d匹配可选带符号的十进制整数,其格式为 与预期的主题序列相同 strtol公司 具有的函数
    基本参数的值10。相应的参数应为 指向有符号整数的指针。

    和(7.22.1.4 strtol、strtoll、strtoul和strtoull功能)

    7. 如果主题序列为空或没有预期的 形式,不进行转换; nptr的值存储在 由endptr指向的对象,前提是endptr不是null 指针。

    因此,在演示程序中,将执行else语句,因为(C标准,7.21.6.2 fscanf函数)

    16如果输入 在第一次转换(如果有)完成之前发生故障。 否则,函数返回 分配的输入项目数, 可以小于规定值,甚至为零 ,如果 早期匹配失败

        2
  •  2
  •   David C. Rankin    7 年前

    实际上,所有没有花时间完全理解 scanf 函数族,然后再尝试使用它进行用户输入。

    在了解具体情况之前,任何时候接受用户输入时,都必须 验证 输入。这意味着检查用于验证输入的任何函数的返回,如果需要,验证接收的输入是否在代码的预期/可接受值范围内。使用 scanf公司 也没什么不同。

    用户输入的首选方法是 fgets 因为它避免了 scanf公司 并完全消耗每一行输入(前提是缓冲区足够大,或者在验证最后读取的字符是否为 '\n' )

    具有 scanf公司 ,则由您来解释和删除保留在中的任何字符 stdin 如果(1)输入成功或(2)输入或匹配失败,随后会有更多的输入尝试。

    安全使用 scanf公司 对于用户输入,您需要测试三个条件:(1)返回是否指示 设置字符串格式 发生了什么?如果是,请清空 标准DIN 并根据需要检查接收到的值的范围。(2) 用户是否按取消输入 Ctrl+d (或 Ctrl+z 在windoze上)。如果是这样,请优雅地退出,确保最终 “\n” 在输出中提供--(取决于操作系统和编译器);最后(3)是否发生匹配或输入故障?如果是,请处理错误并清空 标准DIN .

    当您接受用户输入时,无效输入对您没有好处。因此,您通常希望循环,直到收到有效输入或用户取消为止,这可以通过简单的无限循环相对容易地完成,例如:。

    /** empty all characters reamining in stdin */
    void empty_stdin()
    {
        int c = getchar();
    
        while (c != '\n' && c != EOF)
            c = getchar();
    }
    ...
    
        for (;;) {          /* loop until valid input or user cancels */
            int rtn = 0;    /* variable to capture scanf return */
    
            /* printf() displays the formatted output */
            printf ("Enter an integer: ");
    
            /* scanf() reads the formatted input and stores them */
            rtn = scanf ("%d", &number);
    
            if (rtn == 1) {         /* we got an integer value */
                empty_stdin();      /* empty any remaining characters */
                break;              /* continue with program */
            }
            else if (rtn == EOF) {  /* user canceled with ctrl+d (ctrl+z on win) */
                fprintf (stderr, "user canceled input.\n");
                return 1;
            }
            /* handle input or matching failure */
            fprintf (stderr, "error: matching or input failure occurred.\n");
            empty_stdin();          /* empty any remaining characters */
        }
    

    在输入循环中单步执行时,您会注意到必须检查的三个条件中的每一个都得到了处理,并且保留在 标准DIN 清空,为下一次输入做好准备。完整的代码只输出成功输入的结果(如果在windows上,则添加最终 getchar(); 要防止在使用IDE运行时关闭终端窗口,请执行以下操作:。

    #include <stdio.h>
    
    /** empty all characters reamining in stdin */
    void empty_stdin()
    {
        int c = getchar();
    
        while (c != '\n' && c != EOF)
            c = getchar();
    }
    
    int main (void) {
    
        int number = 0;
    
        for (;;) {          /* loop until valid input or user cancels */
            int rtn = 0;    /* variable to capture scanf return */
    
            /* printf() displays the formatted output */
            printf ("Enter an integer: ");
    
            /* scanf() reads the formatted input and stores them */
            rtn = scanf ("%d", &number);
    
            if (rtn == 1) {         /* we got an integer value */
                empty_stdin();      /* empty any remaining characters */
                break;              /* continue with program */
            }
            else if (rtn == EOF) {  /* user canceled with ctrl+d (ctrl+z on win) */
                fprintf (stderr, "user canceled input.\n");
                return 1;
            }
            /* handle input or matching failure */
            fprintf (stderr, "error: matching or input failure occurred.\n");
            empty_stdin();          /* empty any remaining characters */
        }
    
        /* printf() displays the formatted output */
        printf ("You entered: %d\n", number);
    
    #if defined (_WIN32) || defined (_WIN64)
        getchar ();     /* to hold terminal open -- don't use getch() */
    #endif
    
        return 0;
    }
    

    使用/输出示例

    $ ./bin/scanf_int
    Enter an integer: apples
    error: matching or input failure occurred.
    Enter an integer: a 10 b 50 c 90
    error: matching or input failure occurred.
    Enter an integer: 12345aaa
    You entered: 12345
    

    输入已取消的示例。(注意:在Win10上,ctrl+z不会生成 EOF 默认情况下,请参见 CTRL+Z does not generate EOF in Windows 10 | PROC-X.com )

    $ ./bin/scanf_int
    Enter an integer: NO!
    error: matching or input failure occurred.
    Enter an integer: user canceled input.
    

    仔细检查一下,如果你还有其他问题,请告诉我。

        3
  •  1
  •   jmowla    7 年前

    我认为“scanf()”不会将“a”读作数字,而是简单地跳过在“number”中放入任何数字,29是堆栈中找到的数字的初始值!

    尝试用123之类的东西初始化“number”,您将在输出中得到123。

        4
  •  1
  •   John Bode    7 年前

    %d 期望在输入流中看到一个或多个十进制数字; ’a’ 不是十进制数字,因此 匹配失败 - number 未更新, a 留在输入流中,并且 scanf 返回0以指示未发生转换和赋值。

    因为您不初始化 数字 声明时,它包含 不确定的 值,在本例中为 29 .

    C不会对意外输入使用异常-您必须检查 scanf公司 .

    int result = scanf( “%d”, &number );
    if ( result == 1 )
    {
      // user entered one or more decimal digits for number
    }
    else if ( result == 0 )
    {
      // user entered something that isn’t a decimal digit
    }
    else // result == EOF
    {
      // EOF or error detected on input
    }