每当我们写一个用双引号括起来的字符串时,C语言自动为我们创建一个字符数组,包含该字符串,并以\0字符结尾。
在这种情况下,这些注释略有误导性。我需要更新它们。
当你像这样写东西时:
char *p = "Hello";
或者
printf("world!\n");
C语言会自动为您创建一个字符数组,大小恰好适合包含以\0
结尾的字符串。
但在数组初始化程序的情况下,情况略有不同。当您编写以下内容时:
char b[2] = "hi";
这个字符串只是你要创建的数组的初始化器。因此,你完全可以控制数组的大小。有几种可能性:
char b0[] = "hi"; // compiler infers size
char b1[1] = "hi"; // error
char b2[2] = "hi"; // No terminating 0 in the array. (Illegal in C++, BTW)
char b3[3] = "hi"; // explicit size matches string literal
char b4[10] = "hi"; // space past end of initializer is always zero-initialized
对于
b0
,你没有指定大小,所以编译器使用字符串初始化程序选择正确的大小,这将是3。
对于
b1
,你指定了一个大小,但它太小了,所以编译器应该给你一个错误。
对于
b2
,这是你问的情况,你指定了一个大小,它刚好足够存放字符串初始化程序中的显式字符,但不包括结尾的
\0
。这是一个特殊情况。它是合法的,但你在
b2
中得到的不是一个正确的空结尾字符串。由于它最多只是不寻常,编译器可能会给你一个警告。有关此案例的更多信息,请参见
this question。
对于
b3
,你指定了一个大小,它刚好适合,所以你得到一个正确大小的字符串数组,就像
b0
一样。
对于
b4
,你指定了一个太大的大小,虽然这没有问题。数组中会有额外的空间,超出了结尾的
\0
。(事实上,这个额外的空间也将被填充为
\0
。)这个额外的空间可以让你安全地做一些像
strcat(b4, ", wrld!")
这样的事情。
不用说,大多数时候你会想使用
b0
形式。计算字符是繁琐且容易出错的。正如C语言的创造者之一Brian Kernighan在这个背景下所写的那样,“让计算机做脏活。”
还有一件事。你写道:
and yet the compiler is reorganizing the memory store instructions so that a
and c
are stored before b
in memory to make room for a \0
at the end of the array.
我不知道那里发生了什么,但可以肯定的是编译器并没有试图“为 \0 留出空间”。编译器可以并经常以它们自己难以捉摸的内部顺序存储变量,既不匹配您声明它们的顺序,也不匹配字母顺序或其他任何您可能想到的顺序。如果在您的编译器下数组 b 之后有额外的空间,其中包含一个像终止字符串一样的 \0,那可能基本上是随机的机会,而不是因为编译器试图对您进行帮助,使得 printf("%s\n", b) 这样的东西更好地定义。(在我尝试过的两个编译器下,printf("%s\n", b) 打印了 hi^E 和 hi ??,清楚地显示了预期的尾随随机垃圾的存在。)
b
初始化为从字符串字面值中取出的前两个字符,但不包括空字符终止符。(b
不是一个字符串)。 - William Pursellchar *array_of_strings[] = {"hi", "mom"};
。你可以称之为字符串(如果它有一个0终止符,也就是ASCII nul(不是NULL,@Baard)),或者你可以称之为字符数组。 - Peter Cordes