这是代码-
int main() {
char c = 'A';
char *p = &c;
char *str = "Hello";
printf("%s %s", p, str);
return 0;
}
输出如下
A????? Hello
A?*??? Hello
A?z??? Hello
A???? Hello
A????? Hello
A??y?? Hello
A?*?? Hello
A?Z??? Hello
A?*+?? Hello
A?l?? Hello
A?z?? Hello
A??i?? Hello
A?ʜ?? Hello
现在我知道%s试图寻找一个'\ 0'来停止打印,这就是为什么char指针 str 输出完美的原因。
但是我想知道的是,当我们将char *指向单个字符时,它会在实际的char之后打印一些垃圾值-如何决定每次4或5个垃圾值后停止输出?此安全检查如何工作?据了解,“?” 可能是字符串的一部分。
答案 0 :(得分:6)
对于格式"%s"
,相应的参数必须指向有效的C字符串,这意味着它必须满足两个条件:(1)必须为char*
类型(或{{1 }}),并且(2)它必须指向一个对象,该对象表示在对象边界内以const char*
结尾的字符序列。
如果您这样做
'\0'
然后变量char c;
char* ptr = &c;
仅满足第一个条件;它是一个ptr
,但是它指向的对象仅包含一个字符,如果该字符不是char *
,则char“序列”不会在对象的边界内终止。
因此,'\0'
将访问对象外部的内存,从而产生未定义的行为。一种这样的行为可能是,它只是继续读取内存(即使它不是拥有的),直到遇到printf
为止。这就是您可能正在观察的。
答案 1 :(得分:2)
在printf中,转换说明符s
[已加强调] :
writes a character string
该参数必须是指向字符数组的初始元素的指针。精度指定要写入的最大字节数。 如果未指定Precision,则写入每个字节,直到不包括第一个空终止符为止。如果使用l说明符,则参数必须是指向wchar_t数组的初始元素的指针,该数组将被转换为char数组,就像通过调用零初始化转换状态的wcrtomb一样。
在此声明中:
printf("%s %s", p, str);
p
指向char
类型变量c
的指针,并且您正在使用%s
格式说明符。请注意,如果未使用转换说明符s
指定精度,则它将写入字节,直到找到空终止符为止。 %s
格式说明符,当写入p
所指向的字节时,将从p
所指向的内存开始写入字节,直到找到空终止符为止。这意味着,它可能会访问对象c
拥有的内存以外的内存。读取程序不拥有的内存是未定义的行为,其中包括程序执行可能不正确(崩溃或无提示地生成不正确的结果),或者可能偶然地执行了程序员想要的操作。
您可以执行以下操作:
printf("%.1s %s", p, str);
^^
precision of the conversion
使用%.1s
,它将仅从p
所指向的存储位置读取一个字符。
答案 2 :(得分:1)
这将产生不同的结果。主要是意料之外的结果。尝试在其他计算机(例如,不同的在线C编译器)上运行代码。您将能够看到不同的结果。永远都是意料之外的。
答案 3 :(得分:1)
这就是“不确定行为”的魔力。您无法预测将会发生什么或它将如何表现。 在不同的环境中,更有可能产生不同的结果,所以...