在学习多维数组时,我想把我所创建的多维数组,以及对数组的操作结果,标准输出出来,验证代码是否正确。
用for循环有两种方法:
- 传统的for循环,可以索引下标或对迭代器进行操作
- 范围for循环
constexpr size_t rowCnt = 3, colCnt = 4; //三行四列的容量
int iarr[rowCnt][colCnt]; //默认初始值为0的二维数组
for (size_t j = 0; j != rowCnt; ++j) {
for (size_t k = 0; k != colCnt; ++k) {
iarr[j][k] = j*colCnt + k; //对数组元素进行操作
}
}
数组改变后,需要标准输出。我先尝试了for循环索引下标的方法:
for (size_t i = 0; i!= rowCnt;++i){
for (size_t j=0;j!=colCnt;++j){
cout << iarr[i][j] << " ";
cout << endl;
}
}
接着我尝试了 范围for循环的方法:
for (auto row:iarr){
for (auto item:&row){
cout << item << " ";
}
cout << endl;
}
看似正确,但却没那么简单。代码出错了。
经过一番研究,找到了问题所在,修改后的代码如下:
for (auto &row : iarr) {
for (auto &item : row) {
cout << item << " ";
}
cout << endl;
}
将row和item都修改成引用类型。由前面的学习可值,引用类型可直接修改引用对象的值,那么和数组又是什么关系呢?
引用类型修改元素的值,代码如下:
//引用类型修改数组的元素
size_t cnt = 0;
for (auto &row : iarr) {
for (auto item : row) {
item = cnt; //对item赋值,就是对元素进行赋值
++cnt;
}
}
下面分析原因:
//数组作为auto语句变量初始值 代码3
int ia_test[] = { 0,1,2,3,4,5 };
auto ia2_test(ia_test); //ia2_test是一个指针,指向ia_test的首元素
//尝试对ia2_test赋值
ia2_test = 5; //错误:无法从int转换为 int*
auto ia2_test = ia_test[0]; //实际上编译器所执行的语句
//decltype能够避免数组转换为指针 代码4
int ival_t = 5;
int *p_t = &ival_t; //p是一个整型指针
decltype(ia_test) ia3_test = { 0,1,2,3,4,5 };
ia3_test = p_t; //错误
ia3_test[4] = 42; //正确:说明ia3_test是一个数组
- 浅层:使用引用类型在循环中进行写操作
- 深层:外层循环声明成引用类型,是为了避免数组被自动转化成指针,初始化row时得到指向iarr首元素的指针,内层循环将试图在一个 int*内进行遍历
- 当数组作为一个auto变量的初始值时,推断得到的类型是指针而非数组(代码3)
- 补充:
- 大多数情况下,数组名其实是指向数组首元素的指针
- 当使用decltype时,不会发生上述的转换(代码4)
- 补充:
- 当数组作为一个auto变量的初始值时,推断得到的类型是指针而非数组(代码3)
总结:
- 要使用范围for语句处理多维数组,除了最内层的循环外,其他所有的循环控制变量都应该是引用类型。
「C++Primer 5th」3.6 多维数组 P114
排版上有待进步。
ask:2017/03/15;sloved:2017/03/15;commit:2017/03/26