3.6 多维数组
严格来说, C++中没有多维数组, 通常所说的多维数组其实是数组的数组.
当一个数组的元素仍然是数组时, 通常使用两个维度来定义它: 一个维度表示数组本身大小, 另外一个维度表示其元素(也是数组)大小
int ia[3][4]; //大小为3的数组,每个元素是含有4个整数的数组
对于二维数组来说, 通常把第一个维度称作行, 第二个维度称作列
多维数组的初始化
允许使用花括号括起来的一组值初始化多维数组.
int ia[3][4] = { //3个元素,每个元素都是大小为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 }};
其他未列出的元素执行默认初始化.
这种情况下如果再省略内层地花括号, 结果就不一样了
//显示地初始化第一行,其他元素执行值初始化
int ix[3][4] = {0, 3, 6, 9};
它初始化的是第一行地4个元素, 其他元素被初始化为0
多维数组的下标引用
可以使用下标运算符来访问多维数组地元素, 此时数组的每个维度对应一个下标运算符.
如果表达式含有的下标运算符数量和数组的维度一样多, 该表达式地结果将是给定类型地元素. 反正, 如果表达式含有的下标运算符数量比数组的维度小, 则表达式地结果将是给定索引处的一个内层数组
//用arr的首元素为ia最后一行的最后一个元素赋值
ia[2][3] = arr[0][0][0];
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;
}
在上面例子中, 因为要改变数组元素的值, 所以我们选用引用类型作为循环控制变量, 但其实还有一个深层次的原因粗疏我们这么做. 举一个例子, 考虑下面的循环
for(const auto &row : ia)
for(auto col : row)
cout<< col <<endl;
这个循环中并没有任何写操作, 但我们还是将外层循环的控制变量声明称了引用类型, 这是为了避免数组被自动转成指针. 假设不用引用类型, 则循环如下述形式
for(auto row : ia)
for(auto col : row)
程序将无法通过编译.
这是因为row不是引用类型, 所以编译器初始化row时会自动将这些数组形式的元素转换成指向该数组内首元素的指针. 这样得到的 row 的类型就是int* ,显然内层的循环就不合法了, 编译器将试图在一个int*内遍历.
指针和多维数组
当程序使用多维数组的名字时, 也会自动将其转换成指向数组首元素的指针.
因为多维数组实际上是数组的数组, 所以由多维数组名转换的来的指针实际上是只想第一个内层数组的指针
int ia[3][4];
int (*p)[4] = ia; //p指向含有4个整数的数组
p = &ia[2]; //p指向ia的尾元素
根据从数组的名字开始按照由内向外的顺序阅读这一策略, 我们首先明确(*p)意味着p是一个指针, 观察右边, 指针p所指的是一个维度为4的数组, 再观察左边, 数组中的元素是整数.因此, p就是指向含有4个整数的数组的指针.
通过使用auto或者decltype就能尽可能地避免在数组前面加上一个指针类型了
//输出ia中每个元素的值, 每个内层数组各占一行
//p指向含有4个整数的数组
for(auto p = ia; p != ia + 3; ++p){
//q指向4个整数数组的首元素,也就是说,q指向一个整数
for(auto q = *p; q != *p + 4; ++q)
cout<< *q << ' ';
cout<<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)
cout<< *q <<endl
cout<<endl;
}