#include<stdio.h>
int main(void) {
char str[3];
scanf("%3s", str);
return 0;
}
如果只输入一个字符,str[2]的内容是什么?这是未定义的行为还是所有剩余字符都会用 ' ' 填充?
我尝试了这个,其余的字符都是“”,但这可能是编译器特定的。
C 字符串是字符数组。该字符串以空终止字符终止。
要存储 3 个字符 + 空终止字符,您需要 4 个元素的字符数组。
如果用户输入
scanf
或更多字符,您的 3
将调用未定义的行为。
如果我只输入一个字符,
的内容是什么?这是 未定义的行为或者所有剩余的字符都将被填充 ' '?str[2]
由于您的变量具有自动存储持续时间,因此值
str[2]
无法确定(可以是任何值)。
如果
str
数组具有静态存储持续时间(即在具有static
属性的函数内部定义或者是全局的),那么它将具有0
值(因为未初始化的静态存储持续时间对象在调用之前被归零) main
功能已完成。
处理
s
转换的规则,在 C 2018 7.21.6.2 中说:
…相应的参数应该是一个指向字符数组的初始元素的指针,该数组足够大以接受序列和一个终止空字符,它将自动添加…
这告诉我们,如果您输入一个(非空白)字符(并且可能后面跟着一个空白字符或某种输入结束指示),该字符将被放入
str
(位于 str[0]
),并在其后的 str
中放入一个空字符。
标准没有规定在这些之后向
str
的任何元素写入任何内容。
请注意,
%3s
最多允许读取三个字符,在这种情况下,str
中需要四个元素,以便它可以容纳三个字符和终止空字符。
如果只输入一个字符,str[2]的内容是什么?
内容是不确定的,因为这是一个从未初始化的本地数组。
scanf
(系列)与 %3s
一起使用仅保证最多读取 3 个字符 - 但如果用户键入一个字母,然后输入一个空格字符,scanf
将停在那里,仅读取输入的一个字符。
它还在输入后附加一个空终止符,因此如果用户恰好键入 3 个字符然后按 Enter 键,
scanf
会将空终止符写入越界。
您可以自己尝试使用这个打印缓冲区的二进制内容的小程序:
#include <stdio.h>
int main(void)
{
char str[4]={1,2,3,4};
scanf("%3s", str);
printf("%.2X %.2X %.2X %.2X", str[0], str[1], str[2], str[3]);
}
这里为了说明目的,我将大小更改为 4 并初始化了数组。
输入:
A <enter>
41 00 03 04
41
是'A'
的ASCII值,00
是附加的空终止符,03 04
是之前内存中的内容。如果这是一个未初始化的数组,那么这些值可能是“垃圾”。正如我们所看到的, scanf
not 对数组的剩余部分进行“零填充”(例如 strncpy
会做的事情)。
输入:
ABC <enter>
41 42 43 00
41 42 43
是字母,00
是附加的空终止符。如果这是一个大小为 3 的数组,那么它就会越界。 scanf
不知道数组有多大,所以如果我使用scanf
并传递给它一个%3s
数组,我就会对char [3]
撒谎,说“嘿,你可以在这里存储3个字符+空终止”,即使没有任何空间了。