5.4.2 二维数组的初始化
了解了二维数组的定义方式,下面就将表 5.1 中的成绩数值存储到二维数组中。
像一维数组一样,二维数组在定义的同时,也可以对其进行初始化,将各数组元素初始化为指定的值。下面就用初始化的方式将成绩存储到二维数组 score 中。
1.普通初始化方式
我们可以像一维数组的初始化一样,将表格中的所有成绩值都放入初始值列表中。例如:
float score[3][4] = {88.5, 86.5, 95, 87, 68, 70, 98.5, 92.5, 75.5, 69.5, ?96.5, 84};
由于 score 是一个 3 行 4 列的二维数组,所以,编译器会从初始值列表中每次读取 4 个初始值,将其初始化给所对应行的各元素。即将前 4 个初始值初始化给第 1 行的 4 个元素,将中间 4 个初始值初始化给第 2 行的 4 个元素,将最后的 4 个初始值初始化给第 3 行的 4 个元素。
对二维数组进行初始化时,我们甚至可以省略掉数组定义中的第一维的大小,即采用空中括号的形式,而由编译器根据初始值列表中初始值的个数来确定第一维的大小。例如:
float score[][4] = {88.5, 86.5, 95, 87, 68, 70, 98.5, 92.5, 75.5, 69.5, 96.5, 84};
由于编译器知道数组的第二维的大小为 4,而初始值列表中共有 12 个初始值,所以可以确定数组的第一维大小应该为 3。试想一下,如果在初始值列表中再增加一个初始值,即共有 13 个初始值,那么编译器会将第一维的大小确定为多少呢?
答案为 4。因为 3 行 4 列的二维数组最多只能容纳 12 个数组元素,而 13 个初始值需要对应有 13 个数组元素,所以,编译会将数组的第一维的大小设置为 4,即定义一个 4 行 4 列、能容纳 16 个数组元素的二维数组。
需要注意的是,千万不要省略第二维的大小。因为第一维的大小是根据第二维的大小和初始值的个数来确定的,如果第二维的大小也被省略,那编译器就无能为力了,即使设置了第一维的大小,第二维的大小也不可被省略,第二维的大小必须有一个确定的值。编译器可以根据第二维的大小来确定第一维的大小,但不能根据第一维的大小来确定第二维的大小,也就是无论第一维的大小是否被省略,第二维的大小都必须是确定的。
当初始值列表中初始值的个数少于数组元素的个数时,编译器会按照数组元素的排列顺序,将前面的数组元素初始化为对应的初始值,而将没有对应初始值的数组元素初始化为 0。
假设,由于江天昊同学在数学考试中作弊,现要求取消他的数学成绩,可以这样初始化化二维数组:
float score[3][4] = {88.5, 86.5, 95, 87, 68, 70, 98.5, 75.5, 69.5, 96.5, 84};
我们将原来第 2 行第 4 列的数据,也就是江天昊同学的数学成绩“92.5”从初始值列表中删除了,现在初始值列表中只有 11 个初始值,那么编译器会将数组中的前 11 个数组元素初始化为各初始值,而将第 12 个元素初始化为 0。
这种简单粗暴的删除方式,会带来什么样的后果呢?我们把初始化后二维数组中的数据体现到成绩表中,如表 5.2 所示。
表 5.2 成绩表
表中江天昊的数学成绩依然存在,只不过变成了林妙妙之前的英语成绩。不仅如此,林妙妙的英语成绩变成了邓小琪的英语成绩,邓小琪的英语成绩变成了钱三一的英语成绩,钱三一的英语成绩变成了江天昊的英语成绩,而江天昊的英语成绩变成了 0 分。也就是从江天昊的数学成绩开始,所有的数据都乱了。
所以,正确的处理方式应该是将原来的江天昊的数学成绩,由 92.5 修改为 0,而不是将其直接从初始值列表中删除。即:
float score[3][4] = {88.5, 86.5, 95, 87, 68, 70, 98.5, 0, 75.5, 69.5, 96.5, 84};
现在再把初始化后的二维数组数据对应到成绩表中,如表 5.3 所示。
表 5.3 成绩表
终于对了!是不是还心有余悸?这样的初始化方式有点可怕,稍微不小心,就可能导致数据的存储错误,有什么更好的办法吗?
下面介绍另一种二维数组的初始化方式。
2.行初始化方式
所谓行初始化方式,就是在初始值列表中,以行为单位,将对应的各行初始值再次使用大括号括起来。例如:
在初始值列表里,又分别使用了三对大括号:第一对大括号中包含的是表格中第 1 行的 4 个成绩值,第二对大括号中包含的是表格中第 2 行的 4 个成绩值,第三对大括号中包含的是表格中第 3 行的 4 个成绩值。
这样做的好处是,编译器会严格依照初始值列表中的各个大括号来初始化二维数组中所对应的那一行中的数组元素,即编译器总会将第一对大括号中的初始值初始化给数组中第 1 行的数组元素,将第二对大括号中的初始值初始化给数组中第 2 行的数组元素,将第三对大括号中的初始值初始化给数组中第 3 行的数组元素。
现在,如果在数组初始化的时候,直接删掉江天昊的数学成绩,会出现什么样的情况呢?例如:
编译器首先会将第一对大括号中的 4 个成绩初始化给 score 数组第 1 行的 4 个元素,然后将第二对大括号中的 3 个成绩初始化给 score 数组第 2 行的前 3 个元素,并将第 4 个元素初始化为 0,最后将第三对大括号中的 4 个成绩初始化给 score 数组第 3 行的 4 个元素。初始化后 score 数组中各元素的值对应到成绩表的情况,与表 5.3 一致。
我们删除了第二对大括号中的初始值,只会影响 score 数组中第 2 行的数组元素的初始化情况,而不会影响其他行的数组元素,这就是使用行初始化方式的好处。
在对二维数组使用行初始化方式时,如果省略了第一维的大小,那么编译器就会根据初始值列表中大括号的数量来确定第一维的大小,即有多少对大括号,第一维的大小就是多少。例如,我们定义了二维数组 a,并使用行初始化的方式:
int a[][3] = {{},{},{}};
二维数组 a 第一维的大小被省略,第二维的大小为 3。由于初始值列表中共有 3 对大括号,因此编译器会将第一维的大小确定为 3。即数组 a 的总的元素个数为 9,而数组的大小就是 36 字节。下面通过 sizeof 运算符进行验证:
printf("Size of the a : %u Bytes.\n", sizeof a);
运行结果为:
Size of the a : 36 Bytes.
由于初始值列表中 3 对大括号内都是空的,所以二维数组 a 中的所有(9 个)元素全被初始化为 0。
3.指定初始化方式
在对二维数组进行初始化时,也可以选择指定初始化的方式,即只对所指定位置的数组元素给予初始值,其他位置的元素则被初始化为 0。这对于数组中只有少量数组元素需要初始值时,非常有用。
在对一维数组使用指定初始化方式时,我们需要在初始值的前面指定数组元素的下标。同样地,在对二维数组使用指定初始化方式时,也需要在初始值的前面指定数组元素的下标。所不同的是,对于一维数组只需要一个下标,而对于二维数组则需要两个下标。下标值都是从 0 开始,第一个下标可以指定数组元素所对应的行,第二个下标可以指定数组元素所对应的列。
例如,现在只要求在二维数组中存储邓小琪的三门课程的成绩,可以这样赋值:
float score[3][4] = {[0][1] = 86.5, [1][1] = 70, [2][1] = 69.5};
在初始值列表中只有 3 个初始值,第 1 个初始值前面的两个下标分别是“0”和“1”,这表示将数组中第 1 行第 2 列的数组元素初始化值为 86.5。同理,后面两个初始值分别会初始化给数组中第 2 行第 2 列的数组元素和第 3 行第 2 列的数组元素。
初始化后,二维数组数据对应到成绩表中的数据见表 5.4。
表 5.4 成绩表
可见,只有邓小琪所对应的三门课程有成绩,其他的成绩全部为 0。
最后,对二维数组使用指定初始化方式的同时,也可以使用非指定初始化的方式,使用方式和效果与一维数组类似,在此不再赘述。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论