严格地说,C++ 中没有多维数组,通常所指的多维数组其实就是数组的数组: |
// array of size 3, each element is an array of ints of size 4 int ia[3][4];
在使用多维数组时,记住这一点有利于理解其应用。
如果数组的元素又是数组,则称为二维数组,其每一维对应一个下标:
ia[2][3] // fetches last element from the array in the last row
第一维通常称为行(row),第二维则称为列(column)。
C++ 中并未限制可用的下标个数,也就是说,我们可以定义元素是数组(其元素又是数组,如此类推)的数组。
多维数组的初始化
和处理一维数组一样,程序员可以使用由花括号括起来的初始化式列表来初始化多维数组的元素。对于多维数组的每一行,可以再用花括号指定其元素的初始化式:
int ia[3][4] = { /* 3 elements, each element is an array of size 4 */ {0, 1, 2, 3} , /* initializers for row indexed by 0 */ {4, 5, 6, 7} , /* initializers for row indexed by 1 */ {8, 9, 10, 11} /* initializers for row indexed by 2 */ };
其中用来标志每一行的内嵌的花括号是可选的。下面的初始化尽管有点不清楚,但与前面的声明完全等价:
// equivalent initialization without the optional nested braces for each row
int ia[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
与一维数组一样,有些元素将不使用初始化列表提供的初始化式进行初始化。下面的声明只初始化了每行的第一个元素:
// explicitly initialize only element 0 in each row
int ia[3][4] = {{ 0 } , { 4 } , { 8 } };
如果省略内嵌的花括号,结果会完全不同:
// explicitly initialize row 0
int ia[3][4] = {0, 3, 6, 9};
该声明初始化了第一行的元素,其余元素都被初始化为 0。
多维数组的下标引用
为了对多维数组进行索引,每一维都需要一个下标。例如,下面的嵌套 for 循环初始化了一个二维数组:
const size_t rowSize = 3; const size_t colSize = 4; int ia [rowSize][colSize]; // 12 uninitialized elements // for each row for (size_t i = 0; i != rowSize; ++i) // for each column within the row for (size_t j = 0; j != colSize; ++j) // initialize to its positional index ia[i][j] = i * colSize + j;
当需要访问数组中的特定元素时,必须提供其行下标和列下标。行下标指出需要哪个内部数组,列下标则选取该内部数组的指定元素。了解多维数组下标引用策略有助于正确计算其下标值,以及理解多维数组如何初始化。
指针和多维数组
与普通数组一样,使用多维数组名时,实际上将其自动转换为指向该数组第一个元素的指针。
<Note>:定义指向多维数组的指针时,千万别忘了该指针所指向的多维数组其实是数组的数组。
因为多维数组其实就是数组的数组,所以由多维数组转换而成的指针类型应是指向第一个内层数组的指针。尽管这个概念非常明了,但声明这种指针的语法还是不容易理解:
int ia[3][4]; // array of size 3, each element is an array of ints of size 4 int (*ip)[4] = ia; // ip points to an array of 4 ints ip = &ia[2]; // ia[2] is an array of 4 ints
定义指向数组的指针与如何定义数组本身类似:
首先声明元素类型,后接(数组)变量名字和维数。
窍门在于(数组)变量的名字其实是指针,因此需在标识符前加上 *。
如果从内向外阅读 ip 的声明,则可理解为:*ip 是 int[4] 类型——即ip 是一个指向含有 4 个元素的数组的指针。
<Note>: 在下面的声明中,圆括号是必不可少的: |
int *ip[4]; // array of pointers to int int (*ip)[4]; // pointer to an array of 4 ints
用 typedef 简化指向多维数组的指针
typedef 类型定义可使指向多维数组元素的指针更容易读、写和理解。以下程序用 typedef 为 ia 的元素类型定义新的类型名:
typedef int int_array[4]; int_array *ip = ia;
可使用 typedef 类型输出 ia 的元素:
for (int_array *p = ia; p != ia + 3; ++p) for (int *q = *p; q != *p + 4; ++q) cout << *q << endl;外层的 for 循环首先初始化 p 指向 ia 的第一个内部数组,然后一直循环到 ia 的三行数据都处理完为止。
++p 使 p 加 1,等效于移动指针使其指向 ia 的下一行(例如:下一个元素)。
内层的 for 循环实际上处理的是存储在内部数组中的 int 型元素值。
首先让 q 指向 p 所指向的数组的第一个元素。
对 p 进行解引用获得一个有 4 个int 型元素的数组,通常,使用这个数组时,系统会自动将它转换为指向该数组第一个元素的指针。
在本例中,第一个元素是int型数据,q指向这个整数。系统执行内层的for 循环直到处理完当前 p 指向的内部数组中所有的元素为止。
当 q 指针刚达到该内部数组的超出末端位置时,再次对p 进行解引用以获得指向下一个内部数组第一个元素的指针。
在 p 指向的地址上加 4 使得系统可循环处理每一个内部数组的 4 个元素。