4.1.5 多维数组
迄今为止,我们定义过的数组都只有一个索引值,它们被称为一维数组。数组还可以有多个索引值,这样的数组被称作多维数组。假设有一块农田,我们在上面种植了豆类作物,每行10株,共12行(因此总共有120株)。我们可以使用下面这条语句,声明一个数组来记录每株作物的产量:
- double beans[12][10];
这条语句声明了一个二维数组beans,第一个索引值是行号,第二个索引值是行内的编号。引用任何一个元素都需要两个索引值。例如,我们可以用下面的语句,设定对应于第三行第五株作物的那个元素的值。
- beans[2][4] = 10.7;
记住,索引值是从0开始的,因此行索引值是2,行内第五株作物的索引值是4。
农民可能有好几块相同的农田,上面以相同的模式种植着豆类作物。假设有8块农田,那么可以用三维数组来记录产量,其声明语句如下:
- double beans[8][12][10];
该数组可以记录每块农田内所有作物的产量,最左边的索引值引用具体的田块。如果我们的豆类种植业已经达到国际规模,则可以使用四维数组,增加的那一维用来表示国家。
数组在内存中的存储方式是使最右边的索引值最快地变化。因此,数组data[3][4]是3个各自包含4个元素的一维数组。该数组的排列如图4-4所示。
正如图4-4中的箭头所指示的那样,数组元素存储在连续的内存区域中。第一个索引值选择数组的某一行,第二个索引值选择这一行内的元素。
注意,本地C++(www.cppentry.com)中的二维数组实际上是一维数组的一维数组。三维的本地C++(www.cppentry.com)数组实际上也是一维数组,其中各个元素又都是一维数组的一维数组。多数时候,这不是我们需要担心的事情,但正如稍后将看到的那样,C++(www.cppentry.com)/CLI数组不是这样。就图4-4中的数组而言,这意味着表达式data[0]、data[1]和data[2]都是一维数组。
数组元素存储在连续的区域中
|
| (点击查看大图)图 4-4 |
1. 初始化多维数组
为了初始化多维数组,我们需要扩展原来初始化一维数组的方法。例如,我们可以用下面这条声明语句初始化二维数组data:
- long data[2][4] = {
- { 1, 2, 3, 5 },
- { 7, 11, 13, 17 }
- };
如上所示,该数组中每行的初值都被包围在各自的大括号内。因为每行有4个元素,所以每组有4个初值,因为data数组共有两行,所以外层大括号内共有两组初值,组与组之间用逗号分开。
我们可以在某行内省略某些初值,这样未获得初值的数组元素将被初始化为0。例如:
- long data[2][4] = {
- { 1, 2, 3 },
- { 7, 11 }
- };
上面为省略掉的初值留出了空间,以便使读者看清省略初值的位置。元素data[0][3]、data[1][2]和data[1][3]没有初值,因此值是0。
如果希望将整个数组初始化为0,我们只需写成:
- long data[2][4] = {0};
如果要初始化更多维的数组,则记住一点:数组中有多少维,初值组就需要多少层嵌套的大括号。
试一试:存储多个字符串
我们可以使用单个二维数组存储多个C型字符串。下面就是一个这样的示例程序:
- // Ex4_04.cpp
- // Storing strings in an array.
- #include <iostream>
- using std::cout;
- using std::cin;
- using std::endl;
-
- int main()
- {
- char stars[6][80] = { "Robert Redford",
- "Hopalong Cassidy",
- "Lassie",
- "Slim Pickens",
- "Boris Karloff",
- "Oliver Hardy"
- };
- int dice = 0;
-
- cout << endl
- << " Pick a lucky star!"
- << " Enter a number between 1 and 6: ";
- cin >> dice;
-
- if(dice >= 1 && dice <= 6) // Check input validity
- cout << endl // Output star name
- << "Your lucky star is " << stars[dice - 1];
- else
- cout << endl // Invalid input
- << "Sorry, you haven't got a lucky star.";
- cout << endl;
- return 0;
- }
示例说明
本示例的要点是数组stars的声明。stars是二维数组,元素的类型为char,该数组可以容纳6个字符串,各字符串可包含80个字符(包括编译器自动添加的终止空字符)。该数组的初始化字符串被包围在大括号之间,相互以逗号分开。
注意:
以这种方式使用数组的缺点之一,是几乎总有一些未被使用的存储单元。本例中所有字符串都小于80个字符,因此数组中各行剩余的元素都被白白浪费掉了。
我们也可以省略数组第一维的大小,而让编译器来算出有多少个字符串,声明如下:
- char stars[][80] = { "Robert Redford",
- "Hopalong Cassidy",
- "Lassie",
- "Slim Pickens",
- "Boris Karloff",
- "Oliver Hardy"
- };
这样声明将使编译器根据指定的初始化字符串的个数确定第一维的大小。因为有6个字符串,所以结果是完全相同的,但是这样可以避免出错的可能性。在这里,我们不能将第二维也省略掉。在二维或者多维数组中,最右边的一维必须是确定的。
注意:
这条声明语句最后的分号不能省略。当为数组提供初值时,人们很容易忘记应该以分号结束。
在下面语句中需要引用某个字符串的位置,我们只需指定第一个索引值:
- cout << endl // Output star name
- << "Your lucky star is " << stars[dice - 1];
单个索引值将选择特定的有80个元素的子数组,输出操作将显示出子数组中终止空字符之前的所有内容。指定的索引值是dice-1,因为dice的值是从1~6,而索引值无疑应该是从0~5。