假设 C 字符串是一个以 null 结尾的字符数组:
const char str1[] = {"abc"};
const char str2[] = {'a', 'b', 'c', '\0'};
const char str3[] = {97, 98, 99, '\0'};
是相同的。
那么为什么可以生成这样的字符串数组:
const char * str_arr[] = {"abc", "ABCD"};
const char * str_arr[] = { str1, str2, str3 };
但不是这样的?:
const char * str_arr[] = { {'a', 'b', 'c', '\0'}, {'A', 'B', 'C', 'D', '\0'} };
fatal error: excess elements in scalar initializer
这些之所以有效,是因为 C 2018 6.7.9 中关于如何处理初始化器的规则:
const char str1[] = {"abc"};
,给出了一个字符串文字来初始化 的数组const char
。6.7.9 14 说“字符类型数组可以由字符串文字或 UTF-8 字符串文字初始化,可以选择用大括号括起来。字符串文字的连续字节(如果有空间或数组大小未知,则包括终止空字符)初始化数组的元素。”const char str2[] = {'a', 'b', 'c', '\0'};
,给出了一个值列表int
(字符常量的类型为int
)来初始化数组。6.7.9 17 告诉我们这些用于按顺序初始化数组的子对象(其元素)。对于这些:
const char * str_arr[] = {"abc", "ABCD"};
,字符串文字列表用于初始化指针数组。请注意,这不是用大括号括起来的字符串文字;它是两个字符串文字,因此与上面的规则不匹配。对于使用字符串文字来初始化指针数组而不是字符类型数组没有特殊规则,因此使用 C 的其他规则进行处理,并且两个字符串文字初始化数组的两个元素。字符串文字指定字符数组。6.3.2.1 3 表示当数组不是 的操作数时sizeof
,一元的操作数&
或用于初始化数组的字符串文字,它会转换为指向其第一个元素的指针。因此,这两个数组(由字符串文字指定的数组)中的每一个都被转换为指向其第一个元素的指针,并且这些指针成为 的初始值str_arr
。const char * str_arr[] = { str1, str2, str3 };
、str1
、str2
、中str3
是数组。如上所述,它们会自动转换为指向其第一个元素的指针,并且这些指针用于初始化str_arr
。为此, 的每个元素
str_arr
都是 aconst char *
,为其提供的初始值设定项是{'a', 'b', 'c', '\0'}
。C 中没有规定 aconst char *
可以用大括号中的值列表来初始化int
。当{'a', 'b', 'c', '\0'}
出现在初始化器中时,它作为数组没有任何特殊含义。它只是一个值列表。如何处理该值列表取决于初始化的上下文。如果有一个要填充的数组,则可以使用列表中的值来填充数组元素。但是没有数组,也没有规则说这个值列表被制作成一个数组并创建一个指向该数组的指针。实际上可以,如果你将它们投射到
const char []
:const char *
你不能用 s数组来初始化 的类型char
(因为指针在哪里?),但你可以用它来初始化 的类型const char[]
,并让它衰减为const char *
。