为什么scanf(“d”和“number”)会产生结果';a';C编程中的as 29?

为什么scanf(“d”和“number”)会产生结果';a';C编程中的as 29?,c,scanf,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() di

我有一个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;
}
#包括
int main()
{
整数;
//printf()显示格式化的输出
printf(“输入一个整数:”);
//scanf()读取格式化的输入并存储它们
scanf(“%d”和编号);
//printf()显示格式化的输出
printf(“您输入了:%d”,编号);
返回0;
}
这里我需要输入一个数字,但我输入了一个字符“a”,结果是29。我期望它会抛出一个异常,但我对一个输出感到惊讶。

我认为“scanf()”没有将“a”读作数字,只是跳过将任何数字放入“number”中,29是堆栈中找到的数字的初始值


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

对于初学者,不带参数的函数main应声明为

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;
}
#包括
内部主(空)
{
整数;
//printf()显示格式化的输出
printf(“输入一个整数:”);
//scanf()读取格式化的输入并存储它们
if(scanf(“%d”,&number)==1)
{
//printf()显示格式化的输出
printf(“您输入了:%d\n”,编号);
}
其他的
{
puts(“无效输入”);
}
返回0;
}
并查看如果您尝试输入字符
'a'
而不是数字会发生什么

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

d匹配可选带符号的十进制整数,其格式为 与使用
基本参数的值为10。相应的论点应为: 指向有符号整数的指针

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

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

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

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


实际上,所有新的C程序员都陷入了同样的陷阱,他们在尝试接受用户输入之前,没有花时间完全理解
scanf
函数族

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

用户输入的首选方法是
fgets
,因为它避免了
scanf
中固有的缺陷,并且完全消耗了每行输入(前提是缓冲区足够大,或者在验证最后读取的字符是否为
'\n'
之前重复调用缓冲区)

使用
scanf
,如果(1)输入成功或(2)输入或匹配失败,随后会有更多的输入尝试,则由您负责解释并删除
stdin
中保留的任何字符

为了安全地使用
scanf
进行用户输入,您需要测试三个条件:(1)返回值是否指示在格式字符串中指定的所有转换都发生了?如果是这样,清空标准DIN,并根据需要检查接收到的数值范围。(2) 用户是否通过按Ctrl+d(或windoze上的Ctrl+z)取消输入。如果是这样,请优雅地退出,确保输出中提供了最终的
“\n”
(取决于操作系统和编译器);最后(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上,则添加一个final
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;
}
取消输入的示例。(注意:在Win10上,ctrl+z默认情况下不会生成
EOF
,请参阅)


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

%d
希望在输入流中看到一个或多个十进制数字;
'a'
不是十进制数字,因此您会得到匹配失败-
数字
未更新,
a
保留在输入流中,而
scanf
将0返回到indicate未发生任何转换和分配

由于您在声明编号时没有初始化编号,因此它包含一个不确定的值,在本例中为
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
}

你从哪里读到C有异常?检查那些可能使你的文档失败的函数的返回值,查看
scanf
sho
$ ./bin/scanf_int
Enter an integer: NO!
error: matching or input failure occurred.
Enter an integer: user canceled input.
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
}