5.1.2 数组变量的初始化
我们已经讲过,可以在变量的声明中用符号“=”连接一个初始化器,当变量创建时,就用初始化器的值来初始化变量,例如:
int x = 6, * p = & x;
如果一个变量以其类型而言是由子变量组成,则它的初始化器必须用一对花括号“{”和“}”围起来。在数学上,我们也是用花括号来形成一个集合的。
既然是子变量,那么,每个子变量也都需要一个初始化器。所以,初始化器是迭代组成的,一个数组变量的初始化器由子变量的初始化器组成,子变量的初始化器用逗号“,”分隔开,用来为对应的元素(子变量)提供初始值,例如:
/*************c0501.c*************/ int main(void) { int studs [5] = {1, 2, 3, 4, 5}; }
在这里,{1, 2, 3, 4, 5}是数组变量studs的初始化器,表达式1、2、3、4、5分别是其每个元素(子变量)的初始化器。表达式1为数组studs的第一个元素提供初始值;表达式2为数组studs的第二个元素提供初始值,后面以此类推。
之所以这里的1、2、3、4、5都没有用花括号围起来,是因为数组studs的每个元素都不再包含子变量。
现在,我们将上面的程序保存为源文件c0501.c,然后用-g选项翻译为可执行程序。在gdb中,将断点设置在右花括号“}”所在的那一行,运行程序,用调试命令“p studs”观察数组的内容。如下面的交互过程所示,gdb以集合的形式显示数组的每个元素:
(gdb)p studs
$1 = {1, 2, 3, 4, 5}
(gdb)
数组元素的初始化器还可以包含一个指示器,用于指定初始化哪个元素。指示器是一个用方括号围起来的元素下标,例如:
/**********c0502.c********/ int main(void) { int a [50] = {[22] = 8}; }
这里,[22] = 8是子变量的初始化器,它由指示器“[22]”、符号“=”,以及一个用于提供实际数值的表达式8组成,该初始化器用于初始化那个下标为22的元素,因为这是指示器指定的元素。
现在,我们将上面的程序保存为源文件c0502.c,然后用-g选项翻译为可执行程序。在gdb中,将断点设置在右花括号“}”所在的那一行,运行程序,用调试命令“p a”观察数组的内容。如下面的交互过程所示,gdb以集合的形式显示数组的每个元素:
(gdb)p a
$1 = {0 <repeats 22 times>, 8, 0 <repeats 27 times>}
(gdb)
和上一个例子不同,这一次gdb的p命令似乎并未显示所有数组元素的值。实际上它已经全部予以显示,只不过比较简略。首先,“0<repeats 22 times>”的意思是有22个重复出现的0(包括已经显示的这个0)。换句话说,数组的前22个元素都是0。然后,中间的8表示第23个元素的值是8;最后,“0<repeats 27 times>”的意思是有27个重复出现的0(包括已经显示的这个0)。换句话说,从第24个元素开始,一直到数组的最后一个元素,它们的值都是0。
如果数组的初始化器里没有指示器,那么,初始化的顺序是按元素的下标顺序进行的,先初始化下标为0的元素,然后是下标为1的元素,其他以此类推;如果初始化器的数量少于元素的数量,则剩余的元素被初始化为0;如果数组的初始化器里有指示器,则后续的初始化将延续指示器的下标进行,直至遇到另一个指示器。
在下面的示例中,数组a中下标为0的元素被初始化为1,下标为1的元素被初始化为2,其余的元素被初始化为0;数组b中下标为0的元素被初始化为3,下标为11的元素被初始化为33,下标为9的元素被初始化为5。紧接着,表达式1用于初始化下标为10的元素,表达式2用于初始化下标为11的元素,剩余的元素统统被初始化为0。
/************c0503.c**********/ int main(void) { int a [22] = {1, 2}, b [22] = {3, [11] = 33, [9] = 5, 1, 2}; }
注意,数组b中下标为11的元素被初始化两次,但它将保留最后一次被初始化的数值2,而不是第一次的数值33。