第3章 3.6 多维数组
【多维数组的初始化】
可以使用花括号括起来的一组值初始化多维数组:
int a[3][4] = {
{0, 1, 2, 3}, // 第1行
{4, 5, 6, 7}, // 第2行
{8, 9, 10, 11} // 第3行
};
当然,内嵌花括号并非必须的,也可以用下面这种方法,它与上面的方法是等价的:
int a[3][4] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
在初始化多维数组的时候也并非所有元素都包含在初始化列表中,如果仅仅想初始化每一行的第一个元素,可以这样,其它没有列出来的元素执行默认初始化。:
int a[3][4] = {{0}, {4}, {8}};
但要注意,在这种情况下,如果省去花括号,结果则不同:
int a[3][4] = {0, 4, 8}; // 这相当于只初始化了第1行的前3个元素,其它元素被初始化为0
【多维数组的下标引用】
可以使用下标运算符来访问多维数组的元素,此时每个数组的维度对应一个下标运算符:
(1)如果表达式含有的 下标运算符数量 与 数组的维度 一样多,则表达式的结果将是 给定类型的元素;
(2)如果表达式含有的 下标运算符数量 比 数组的维度 小,则表达式的结果是给定索引处的一个内层数组:
int a[3][4], b[2][3][4];
int a[2][3] = b[0][0][0]; // 用b的首元素为a最后一行最后一列的元素赋值
int (&row)[4] = a[1]; // 把row绑定到a的第二个4元素数组上
【使用范围for语句处理多维数组】
【注意】使用范围for语句处理多维数组时,除了最内层的循环外,其它所有循环的控制变量都应该是引用类型,这可以避免数组被自动转成指针。
假设不用引用类型:
int a[3][4];
for(auto row : a)
for(auto col : row)
这样程序不会通过编译。因为第一个循环中,由于row不是引用类型,因此编译器初始化row时会自动将其这些数组形式的元素转换成指向该数组内首元素的指针,因此这样得到的row的类型是int ,显然内存循环就不合法了*。上例中正确的写法是:
int a[3][4];
for(auto &row : a)
for(auto &col : row)
【指针和多维数组】
多维数组实际上是数组的数组,所以 由多维数组名转换的来的指针 实际上是 指向第一个内层数组的指针:
int a[3][4]; // a是大小为3的数组,每个元素是含有4个整数的数组
int (*p)[4] = a; // p指向含有4个整数的数组,它指向的是a的第一个元素
p = &a[2]; // p指向a的尾元素
随着C++11新标准的提出,通过使用 auto 和 decltype 就能尽可能避免在数组前加上一个指针类型:
// 输出a中每个元素的值,每个内层数组各占一行
int a[3][4];
// p指向含有4个整数的数组
for(auto p = a; p != a + 3; ++p) {
// q指向4个整数数组的首元素,即q指向一个整数
for(auto q = *p; q != *p + 4; ++q) {
cout << *q << " ";
}
cout << endl;
}
当然,也可以使用标准库函数 begin 和 end:
int a[3][4];
for(auto p = begin(a); p != end(a); ++p) {
for(auto q = begin(*p); q != end(*p); ++q) {
cout << *q << " ";
}
cout << endl;
}
【类型别名简化多维数组的指针】
使用 类型别名 可以简化多维数组的指针,例如:
using int_array = int[4];
typedef int int_array[4]; // 等价的typedef声明
int a[3][4];
for(int_array *p = a; p != a + 3; ++p) {
for(int *q = (*p); q != *p + 4; ++q) {
cout << *q << " ";
}
cout << endl;
}