“聚合”类型是结构、联合或数组类型。 如果聚合类型包含聚合类型的成员,则初始化规则将以递归方式应用。
语法
initializer:
{ initializer-list } /* 针对聚合初始化 */{ initializer-list , }
initializer-list:
initializerinitializer-list , initializer
initializer-list 是用逗号分隔的初始值设定项的列表。 列表中的每个初始值设定项是常量表达式或初始值设定项列表。 因此,可以嵌入初始值设定项列表。 此形式对于初始化聚合类型的聚合成员很有用,如本节中的示例所示。 但是,如果自动标识符的初始值设定项是一个表达式,则它无需是常量表达式;它只需要针对标识符的适当类型的赋值。
对于每个初始值设定项列表,常量表达式的值将按顺序赋给聚合变量的相应成员。
如果 initializer-list 具有的值少于聚合类型,则聚合类型的其余成员或元素将初始化为 0。 未显式初始化的自动标识符的初始值是不确定的。 如果 initializer-list 具有的值多于聚合类型,则会导致错误。 这些规则适用于每个嵌入的初始值设定项列表以及整个聚合。
结构的初始值设定项要么是同一类型的表达式,要么是其成员包含在大括号 ({ }) 中的初始值设定项的列表。 未命名的位域成员是未初始化的。
在初始化联合时,initializer-list 必须是单个常量表达式。 常量表达式的值将赋给联合的第一个成员。
如果数组的大小未知,则初始值设定项的数目将确定数组的大小,并且其类型将变为已完成。 无法在 C 中指定初始值设定项的重复,也无法在数组中间初始化元素而不提供前面的所有值。 如果您的程序中需要此操作,请使用汇编语言编写该例程。
请注意,初始值设定项的数目可以设置数组的大小:
int x[ ] = { 0, 1, 2 }
但是,如果您指定大小并提供错误的初始值设定项数目,则编译器将生成错误。
Microsoft 专用
数组的最大大小由 size_t 定义。 头文件 STDDEF.H 中定义的 size_t 是一个 unsigned int,其范围从 0x00000000 到 0x7CFFFFFF。
结束 Microsoft 专用
示例
此示例演示数组的初始值设定项。
int P[4][3] =
{
{ 1, 1, 1 },
{ 2, 2, 2 },
{ 3, 3, 3,},
{ 4, 4, 4,},
};
此语句将 P 声明为一个四列三行的数组,并将其第一行的元素初始化为 1,将其第二行的元素初始化为 2,将其第三行的元素初始化为 3,将其第四行的元素初始化为 4。 请注意,第三行和第四行的初始值设定项列表在最后一个常量表达式后包含逗号。 最后一个初始值设定项列表 ({4, 4, 4,},) 的后面也跟有一个逗号。 这些额外的逗号是允许的,但不是必需的;只需要将常量表达式彼此分隔开的逗号以及将初始值设定项列表彼此分隔开的逗号。
如果聚合成员没有嵌入的初始值设定项列表,则只会按顺序将值赋给子聚合的每个成员。 因此,前面的示例中的初始化与以下项是等效的:
int P[4][3] =
{
1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4
};
大括号还可以显示在列表中的各个初始值设定项的两边,并有助于阐明上面的示例。
在初始化聚合变量时,您必须谨慎正确地使用大括号和初始值设定项列表。 下面的示例更详细地阐释了编译器的大括号的说明:
typedef struct
{
int n1, n2, n3;
} triplet;
triplet nlist[2][3] =
{
{ { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }, /* Row 1 */
{ { 10,11,12 }, { 13,14,15 }, { 16,17,18 } } /* Row 2 */
};
在此示例中,nlist 声明为结构的 2x3 数组,每个结构具有三个成员。 初始化的第 1 行将值赋给 nlist 的第一行,如下所示:
第 1 行上的第一个左大括号告知编译器 nlist 的第一个聚合成员(即 nlist[0])的初始化已开始。
第二个左大括号指示 nlist[0] 的第一个聚合成员(即 nlist[0][0] 处的结构)的初始化已开始。
第一个右大括号结束 nlist[0][0] 结构的初始化;下一个左大括号开始 nlist[0][1] 的初始化。
此过程将继续,直到右大括号结束 nlist[0] 的初始化的行的末尾。
第 2 行采用类似的方法将值赋给 nlist 的第二行。 请注意,包含第 1 行和第 2 行上的初始值设定项的大括号的外部集是必需的。 忽略外部大括号的下列构造将会导致错误:
triplet nlist[2][3] = /* THIS CAUSES AN ERROR */
{
{ 1, 2, 3 },{ 4, 5, 6 },{ 7, 8, 9 }, /* Line 1 */
{ 10,11,12 },{ 13,14,15 },{ 16,17,18 } /* Line 2 */
};
在此构造中,第 1 行上的第一个左大括号开始 nlist[0](它是三个结构的数组)的初始化。 值 1、2 和 3 将赋给第一个结构的三个成员。 当遇到下一个右大括号(值 3 的后面)时,nlist[0] 的初始化已完成,并且三个结构数组中的其余两个结构将自动初始化为 0。 同样,{ 4,5,6 } 会初始化 nlist 的第二行中的第一个结构。 nlist[1] 的其余两个结构将设置为 0。 当编译器遇到下一个初始值设定项列表 ({ 7,8,9 } ) 时,它会尝试初始化 nlist[2]。 由于 nlist 只具有两个行,因此该尝试会导致错误。
在下一个示例中,x 的三个 int 成员分别初始化为 1、2 和 3。
struct list
{
int i, j, k;
float m[2][3];
} x = {
1,
2,
3,
{4.0, 4.0, 4.0}
};
在上面的 list 结构中,m 的第一行中的三个元素将初始化为 4.0;m 的剩余行的元素将初始化为 0.0(默认值)。
union
{
char x[2][3];
int i, j, k;
} y = { {
{'1'},
{'4'}
}
};
在此示例中,将初始化联合变量 y。 该联合的第一个元素是数组,因此该初始值设定项是聚合初始值设定项。 初始值设定项列表 {'1'} 将值赋给数组的第一行。 由于列表中仅显示一个值,因此,第一列中的元素将初始化为字符 1,而该行中的其余两个元素将初始化为值 0(默认值)。 同样,x 的第二行的第一个元素将初始化为字符 4,而该行中的其余两个元素将初始化为值 0。