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

时间:2017-12-25 22:14:45

标签: c scanf

我在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 个答案:

答案 0 :(得分:3)

对于初学者,没有参数的函数main应声明为

AVPlayer

只需按以下方式更改您的程序

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; } 而不是数字会发生什么。

根据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如果输入,fscanf函数返回宏EOF的值   在第一次转换(如果有)完成之前发生故障。   否则,该函数返回分配的输入项数,   在发生的情况下,可能会少于,甚至为零   早期匹配失败

答案 1 :(得分:2)

你陷入了同样的陷阱,在尝试用它输入用户输入之前,几乎所有没有花时间完全理解scanf函数族的新C程序员陷入困境。

在详细说明之前,无论何时进行用户输入,都必须 验证 输入。这意味着检查用于验证输入的任何函数的返回实际上已接收,并且如有必要,验证收到的输入是否在您的代码的预期/可接受的值范围内。使用scanf也不例外。

用户输入的首选方法是fgets,因为它避免了scanf中固有的陷阱并且完全消耗了每一行输入(假设缓冲区足够大,或者重复调用它直到你验证最后读取的字符是'\n'

使用scanf,如果(1)成功输入或(2)输入或匹配失败,由您自行决定并删除stdin中保留的任何字符其中输入的其他尝试将随之而来。

要安全地使用scanf进行用户输入,您有三个条件需要测试,(1)返回是否表示发生了格式字符串中指定的所有转换?如果是,请清空stdin并检查根据需要收到的值范围。 (2)用户在上按 Ctrl + d (或 Ctrl + z )取消输入。如果是这样,请优雅地退出以确保输出中提供了最终'\n' - (取决于OS&amp;编译器);最后(3)发生匹配或输入失败?如果是,请处理错误并清空stdin中的任何无效字符。

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

/** 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 */
    }

通过输入循环,您将注意到必须检查的三个条件中的每一个都被处理,并且stdin中保留的任何字符都被清空以准备下一个输入。您的完整代码只输出成功输入的结果(如果在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.

仔细看看,如果您有其他问题,请告诉我。

答案 2 :(得分:1)

我认为“scanf()”不会像数字一样读取“a”而只是跳过将任意数字放入“number”中,而29是堆栈中找到的数字的初始值!

尝试用123之类的东西初始化“数字”,你将得到123输出。

答案 3 :(得分:1)

%d期望在输入流中看到一个或多个十进制数字; ’a’不是十进制数字,因此您得到匹配失败 - number未更新,a保留在输入流中,{{1返回0表示没有发生转换和赋值。

由于您在声明时未初始化scanf,因此它包含 indeterminate 值,在本例中为number

C不会对意外输入使用异常 - 您必须检查29的返回值。

scanf