[英]What's the trailing symbols within an char array which initialized with brace-enclosed lists in clang?
#include <stdio.h>
int main(int argc, const char *argv[]) {
char name1[] = {'f','o','o'};
char name2[] = "foo";
printf("%s\n", name1);
printf("%s\n", name2);
return 0;
}
运行上面的代码会导致:
foox\363\277\357\376
foo
Program ended with exit code: 0
那么,这两个初始化器有什么区别呢?
name1
是一个由三个字符组成的数组{'f', 'o', 'o'}
。
name2
是一个由四个字符组成的数组{'f', 'o', 'o', '\0'}
。
printf("%s", ...)
需要一个以 null 字符结尾的数组。 因为name1
不是,所以您开始取消引用超出数组末尾的字符,这可能具有传统的未定义行为。
第一个数组(即{'f','o','o'}
)将没有null
字符'\0'
,而第二个数组(即"foo"
)将。
使用%s
时的printf规范说明如下:
如果不存在 l 修饰符: const char * 参数应为指向字符类型数组的指针(指向字符串的指针)。 数组中的字符最多写入(但不包括)一个终止 null 字节('\0'); 如果指定了精度,则写入的数量不超过指定的数量。 如果给定精度,则不需要存在 null 字节; 如果未指定精度或大于数组的大小,则数组必须包含终止 null 字节。
由于您的printf
不包括精度,因此它将写入数组中的字符,直到到达 null 字节( '\0'
)。 因此,对于char name1[] = {'f','o','o'};
导致 printf 从分配给name1数组的 memory 中写入字符。 这种行为被认为是未定义的。
这就是为什么printf("%s\n", name1);
从 memory 中不应该访问的下一个位置打印foo加上一些额外的符号,而printf("%s\n", name2);
它按原样打印字符串“ foo"
。
数组中没有尾随符号。
但是printf
的%s
格式需要一个string ,而数组name1
不是一个字符串:根据定义, C 字符串是零终止的……而您的数组不是。 因此,行为是未定义的,在您的特定情况下似乎发生的情况是printf
继续打印恰好位于 memory 内容后面的随机值name1
。
在 C 语言中,如果您使用逐字符初始化程序初始化字符串,则需要输入'\0'
,它是 NULL/终止字符以指示字符串的结尾。 所以 name1 应该是{'f', 'o', 'o', '\0'}
您可以在 output 的末尾看到的x\363\277\357\376
只是因为 printf 在字符串名称的末尾找不到“\0”而打印的垃圾值1。
对于 name2,您使用双引号来初始化字符串,该字符串会自动在字符串末尾放置一个'\0'
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.