toa*_*ong 1 c string valgrind null-terminated
在C中,当我以这种方式初始化我的数组时:
char full_name[] = {
't', 'o', 'a', 'n'
};
Run Code Online (Sandbox Code Playgroud)
并打印出来 printf("%s", full_name);
用valgrind运行它我得到了错误
未初始化的值由堆栈分配创建
为什么会这样?
如果你没有提供'\0'逗号分隔括号初始化列表的末尾,从技术上讲,full_name不是字符串,因为char数组不是以空值终止的.
只是为了清除一些东西,不像初始化程序是字符串文字,逗号分隔列表不会自动计数并将终止空字符放入数组中.
所以,如果有像这样的定义
char full_name[] = {
't', 'o', 'a', 'n'
};
Run Code Online (Sandbox Code Playgroud)
阵列的大小是4,它有't','o','a','n'进去.
OTOH,如果是的话
char full_name[] = "toan";
Run Code Online (Sandbox Code Playgroud)
full_name将是大小为5,将包含't','o'和'a','n'并'\0'在其中.
当你尝试使用前一个数组和任何对字符串操作的函数(即,期望一个以null结尾的char数组)时,你将得到未定义的行为,因为大多数字符串函数将超出搜索范围 -终止.
在您的特定示例中,对于%s格式说明符printf(),引用C11标准,章节§7.21.6.1,fprintf()函数说明(强调我的)
s
如果不存在l长度修饰符,则参数应为指向字符类型数组的初始元素的指针.280) 来自数组的字符被写入(但不包括)终止空字符.如果指定了精度,则不会写入多少个字节.如果未指定精度或大于数组的大小,则数组应包含空字符.
这意味着,printf()将寻找一个空终止符来标记/理解数组的结尾.在您的示例中,缺少null终止符将导致printf()超出分配的内存(full_name[3])并访问full_name[4]将导致UB的超出内存().
由于%s格式说明符需要以空字符结尾的字符串,因此未定义代码的结果行为.您的程序被认为是不正确的,可以产生任何输出,不产生输出,崩溃等等.简而言之,不要这样做.
这并不是说,人物的所有阵列必须是空值终止:该规则仅适用于打算作为C字符串,例如用来传递给字符数组printf的%s格式说明,或要传递到strlen或其他字符串函数标准C库.
如果您打算将char数组用于其他内容,则不需要将其终止.例如,这个用途是完全定义的:
char full_name[] = {
't', 'o', 'a', 'n'
};
for (size_t i = 0 ; i != sizeof(full_name) ; i++) {
printf("%c", full_name[i]);
}
Run Code Online (Sandbox Code Playgroud)