考纲要求
- 掌握二维数组的定义方式,理解行下标与列下标的范围。
- 能用双重循环按行优先顺序遍历所有元素。
- 能完成矩阵求和、转置、对角线统计等基础操作。
- 能按题目要求输出指定形状的字符图形。
典型题型
- 读入矩阵并输出转置,或求某一行、某一列的和。
- 统计主对角线或副对角线元素。
- 用二维字符数组输出图形。
常见错误
- 行列下标写反,矩阵被当成转置后的形式处理。
- 遍历时内层用行数、外层用列数,越界访问。
- 二维数组定义时把行列大小写反,访问范围和内存占用都出错。
- 输出图形时忘记在每行末尾换行。
深入理解
第一个下标是行,第二个是列
int a[3][4]; 表示 3 行 4 列,第一个下标范围 0 到 2,第二个 0 到 3。访问 a[i][j] 时,i 是第几行、j 是第几列。
「下标写反」是二维数组最高频的错误,而且往往不会报错,只是结果全错。避免的方法是先固定语义再写代码:如果题目说「第 i 行第 j 列」,那就约定 i 管行、j 管列,全程不要换。遍历时外层走行、内层走列,与日常阅读顺序一致,也不容易乱。
遍历顺序决定能不能一趟算完
按行遍历是 for (i) for (j),按列遍历是 for (j) for (i)。两者的访问顺序不同,有些题目必须用其中一种:例如求每行的最大值,外层走行、内层走列,才能在内层结束后直接得到该行的结果;求每列的和则要反过来。
矩阵转置是最能体现差异的例子:b[j][i] = a[i][j],遍历顺序随意,但两个下标必须对调。写的时候先写 a 的下标,再交换位置填到 b,比死记「行列互换」更不容易错。
传参时必须写清列数
二维数组传参时,行数可以省略,列数不能省略:
void print(int a[][4], int rows) { ... } // 正确
void print(int a[][], int rows) { ... } // 错误原因是指针算术需要知道「每行有多长」才能算出一个元素的位置。列数一旦确定,a[i][j] 的地址就是首地址加上 i * 列数 + j 个元素。如果题目的列数是变量,通常改用 vector<vector<int>> 或者在全局定义数组。
自编例题
输出矩阵的转置
读入 n 行 m 列的矩阵,输出它的转置,即 m 行 n 列。
for (int j = 0; j < m; j++) {
for (int i = 0; i < n; i++) cout << a[i][j] << ' ';
cout << endl;
}转置就是交换行与列,原来的第 i 行第 j 列变成新矩阵的第 j 行第 i 列。输出时外层循环走列、内层循环走行,就相当于按新矩阵的行优先顺序打印。如果直接在原数组上做转置,需要只遍历上三角并交换对称位置的两个元素,保证每对元素只交换一次,否则会换回原样。
相关真题
这块内容在整条路线里的位置:GESP C++ 4 级备考路径。
READY TO START
开始练习
先做一套本级别测评,报告会指出哪些知识点需要重点补;再回到本页对照考纲要求逐条核对,把不确定的条目记下来集中练。
常见问题
二维数组在内存里怎么存放?
按行优先连续存放,先放第 0 行的所有元素,再放第 1 行,以此类推。下标计算依赖这个顺序。
二维数组的行列下标范围是多少?
定义为 a[n][m] 时,行下标是 0 到 n-1,列下标是 0 到 m-1,两个方向都不能越界。
二维数组能作为函数参数吗?
可以,但必须指定列数,例如 void f(int a[][100]),因为编译器需要列数计算元素地址。
