为什么第二个 scanf 也改变了第一个 scanf 中呈现的变量?

Why the second scanf also changes the variate presented in the first scanf?

我想用 scanf 函数输入一个整数和一个字符,但它没有按我的要求工作。

代码如下

#include <stdio.h>
int main()
{
    int a;
    char c;
    scanf("%d",&a);
    scanf("%2c",&c);
    printf("%d%c",a,c);
    return 0;
}

我尝试从终端输入12a a后有一个space),但输出不是“12a”而是“32a”。

我也尝试运行上面的代码一步一步的,发现当运行进入第一个“scanf”时,“a”的值为12,但是当运行进入第二个“scanf”,“a”的值变为32.

我想弄明白为什么第二个scanf改变了a的值,没有给出

引用 C11,第 7.21.6.2 章,fscanf 函数(强调我的

c

[...]If an l length modifier is present, the input shall be a sequence of multibyte characters that begins in the initial shift state. Each multibyte character in the sequence is converted to a wide character as if by a call to the mbrtowc function, with the conversion state described by an mbstate_t object initialized to zero before the first multibyte character is converted. The corresponding argument shall be a pointer to the initial element of an array of wchar_t large enough to accept the resulting sequence of wide characters. [...]

并且您正在提供 char *。提供的参数与预期的参数类型不匹配,因此这是未定义的行为。

因此结果不能自圆其说。

要保存像 "a " 这样的输入,您需要一个(足够长的)char 数组,char 变量是不够的。

问题是编译器将变量 a 放在了变量 c 的后面。当您执行第二个 scanf() 时,您指定将 两个字符 读入一个只有一个 space 的变量。您发生了缓冲区溢出,并覆盖了变量 c 之后的内存(并且 a 恰好在那里)。 space 已写入 a,这就是您获得 32 输出的原因(a 已存储 ASCII SPACE 的值,至极是 32).

发生的事情被称为未定义行为,当您犯这种错误时很常见。您可以通过定义一个 char 单元格数组来解决这个问题,其中至少有两个单元格用于读取这两个字符。然后使用类似的东西:

#include <stdio.h>
int main()
{
    int a;
    char c[2];
    scanf("%d", &a);
    scanf("%2c", c);   /* now c is a char array so don't use & */
    printf("%d%.2s", a, c); /* use %.2s format instead */
    return 0;
}

注:

使用 %.2s 格式说明符是因为 c 是一个由两个字符组成的数组,已完全填充(不允许 space 包含 [= 22=] string end delimiter) 如果我们不确保格式将在第二个字符处结束(或之前,以防在第一个或第二个数组位置中找到真正的 [=22=] ),这将导致未定义的行为)