#include<stdio.h>
void main()
{
int i;
char str[4] = "f4dfkjfj";
char str2[3] = "987";
char str3[2] = {'j','j','\0'};
//printf("%c\n",str[1]);
//printf("%c\n",1[str]);
puts(str);
puts(str2);
puts(str3);
}
输出观察:
str2
打印str2
和str
的内容。str3
打印str3
,str2
和str
。为什么在打印非nul结束字符串时出现这种行为,它与先前定义的字符串连接,直到puts()函数遇到“\ 0”字符(此函数打印直到遇到nul)?
(注意:我故意用太长的初始化字符串初始化它们)
答案 0 :(得分:5)
(注意:我故意用太长的初始化字符串初始化它们)
然后你也应该注意副作用。
包含所有数组的问题,它们不是以空值终止的,因此它们不 字符串。
引用C11
,章节§7.1.1,术语定义,(强调我的)
string 是一个连续的字符序列由第一个null终止并包含 字符即可。 [...]
将它们与字符串处理函数(如puts()
)一起使用会调用 undefined behavior ,因为搜索null-terminator的函数会超出范围(即,在允许的内存区域之外)并导致无效的内存访问。
再次引用标准,第7.21.7.9章,
puts
函数将s
指向的字符串写入stdout
指向的流, 并在输出中附加换行符。终止空字符不是 写入。
期望的参数是 string ,代码中没有任何参数。
即FWIW,对于托管环境,main()
的推荐签名至少为int main(void)
。
答案 1 :(得分:3)
初始化
char str[4] = "f4dfkjfj";
以及
char str2[3] = "987";
和
char str3[2] = {'j','j','\0'};
不正确,因为表达式char str[4]
为数据分配4个字节,但数据 - "f4dfkjfj"
需要9个字节 - 可见字符为8个字节,'\0'
为1个字节。
<强>更新强>
让我们考虑以下示例
#include<stdio.h>
void main()
{
int i;
char str[4] = "f4dfkjfj";
char str2[3] = "987";
printf("Address of str2 = %p and size is %d bytes\n", str2, sizeof(str2));
printf("Addres | Data in memory\n");
char * ptr;
for (ptr = str2 - 2; ptr <= str2 + 5; ptr++)
{
printf("%p | %c\n", ptr, *ptr);
}
}
在Windows 7下的Visual Studio 2013中,我看到以下内容:
但如果我将char str2[3] = "987";
更改为char str2[4] = "987";
,结果将为
puts(str2)
尝试char str2[4] = "987";
,您会看到差异。
注意:每次内存地址(在本地变量的堆栈中)都可以(可以)不同,但是分配的内存(更改或不更改)周围的数据更重要。
答案 2 :(得分:2)
这些行是约束违规。编译器应该给出一条错误消息,并且程序的行为是完全未定义的:
char str[4] = "f4dfkjfj";
char str3[2] = {'j','j','\0'};
违反的约束是阵列的初始化程序太多。 (C11 6.7.9 / 2)
但是char str2[3] = "987";
是正确的,有一种特殊情况,当从字符串文字初始化数组时,如果数组中没有空间,则允许忽略空终止符。 (C11 6.7.9 / 14)
继续将str2
传递给期望以null结尾的字符串的函数会导致未定义的行为。