3.6 多维数组
3.6 多维数组
通常所说的多维数组其实是数组的数组。
当一个数组的元素仍然是数组时,通常使用两个维度来定义它:一个维度表示数组本身大小,另外一个维度表示其元素(也是数组)大小
// 数组定义
int ia[3][4]; // 大小为 3 的数组,每个元素都是含有 4 个整数的数组
int arr[10][20][30]; // 大小为 10 的数组,每个元素都是大小为 20 的数组,这些数组的元素是含有 30 个整数的数组
// 数组下标引用
ia[2][3] = arr[0][0][0];// 用 arr 的首元素为 ia 最后一行的最后一个元素赋值
int (&row)[4] = ia[1]; // 把 row 绑定到 ia 的第二个4元素数组上
通过由内而外的顺序阅读多为数组的定义有助于更好地理解其真实含义。以ia
为例:
我们定义的名字是ia
,显然ia
是一个含有 3 个元素的数组。接着观察右边发现,ia
的元素也有自己的维度,所以ia
的元素本身又都是含有 4 个元素的数组。再观察左边知道,真正存储的元素是整数。因此最后可以明确:ia
定义了一个大小为 3 个数组,该数组的每个元素都是含有 4 个整数的数组。
对于二维数组来说,常把第一个维度称作行(row),第二个维度称作列(col)。
多维数组的初始化
允许使用花括号括起来的一组值初始化多维数组,以下几种方式都可以进行初始化
// 对每行都标识花括号
int ia[3][4] = { // 三个元素,每个元素都是大小为 4 的数组
{0,1,2,3}, // 第一行
{4,5,6,7}, // 第二行
{8,9,10,11} // 第三行
};
// 没有标识每行的花括号
int ia[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
// 显式地初始化每行的首元素
int ia[3][4] = {{0}, {4}, {8}};
多维数组的下标引用
可以使用下标运算符来访问多维数组的元素,此时数组的每个维度对应一个下标运算符。
- 如果表达式含有的下标运算符数量和数组的维度一样多,该表达式的结果将是给定类型的元素;
- 如果表达式含有的下标运算符数量比数组的维度小,则表达式的结果将是给定索引处的一个内层数组
ia[2][3] = arr[0][0][0]; // 用 arr 的首元素为 ia 最后一行的最后一个元素赋值
int (&row)[4] = ia[1]; // 把 row 绑定到 ia 的第二个含有 4 个元素的数组上
使用两层嵌套的for循环来处理多维数组的元素
constexpr size_t rowCnt = 3, colCnt = 4;
int ia[rowCnt][colCnt]; // 12个未初始化的元素
for(size_t i = 0; i != rowCnt; ++i) // 对于每一行
{
for(size_t j = 0; j != colCnt; ++j) // 对于行内的每一列
{
ia[i][j] = i * colCnt + j; // 将元素位置的索引作为它的值
}
}
使用范围 for 语句处理多维数组
size_t cnt = 0;
for(auto &row : ia){ // 对于外层数组的每一个元素
for(auto &col : row){ // 对于内层数组的每一个元素
col = cnt; // 将下一个值赋给该元素
++cnt; // 将 cnt 加 1
}
}
将数组的循环控制变量声明为引用类型,是为了避免数组被自动转换为指针。上例中,如果不使用引用,编译器在初始化row
时会自动将这些数组形式的元素转换成指向该数组内首元素的指针,这样得到的row
的类型就是int *
,显然内层的循环就不合法了。
要使用范围for语句处理多维数组,除了最内层的循环外,其他所有循环的控制变量都应该是引用类型
指针和多维数组
当程序使用多维数组的名字时,也会自动将其转换成指向数组首元素的指针。因为多维数组实际上是数组的数组,所以由多维数组转换得来的指针实际上是指向第一个内层数组的指针。
int ia[3][4]; // 大小为 3 的数组,每个元素是含有 4 个整数的数组
int (*p)[4] = ia; // p 指向含有 4 个整数的数组
// 注意声明中的圆括号
int *p[4]; // 整型指针的数组
p = &ia[2]; // p 指向 ia 的尾元素
可以使用auto
或者decltype
来获取多维数组的指针
/*输出ia中每个元素的值,每个内层数组各占一行*/
for(auto p = ia; p != ia + 3; ++p){ // p指向含有4个整数的数组
for(auto q = *p; q != *p + 4; ++q){ // q指向含有4个整数数组的首元素,也就是说,q指向一个整数
std:cout << *q << ' ';
}
std::cout << std::endl;
}
// 使用标准库函数 begin 和 end 改写的方式
for(auto p = std::begin(ia); p != std::end(ia); ++p){
for(auto q = std::begin(*p); q != std::end(*p); ++q){
std:cout << *q << ' ';
}
std::cout << std::endl;
}
类型别名简化多维数组的指针
可以使用类型别名对一个指向多维数组的指针进行读、写。
using int_array = int[4]; // 新标准下类型别名的声明
typedef int int_array[4]; // 等价的 typedef 声明
// 输出 ia 中每个元素的值,每个内层数组各占一行
for(int_array *p = ia; p != ia + 3; ++p){
for(int *q = *p; q != *p + 4; ++q){
std:cout << *q << ' ';
}
std::cout << std::endl;
}