为什么第二个 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=]
),这将导致未定义的行为)
我想用 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 thembrtowc
function, with the conversion state described by anmbstate_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 ofwchar_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=]
),这将导致未定义的行为)