CCF GESP 考级专项讲义:二维与多维数组全阶应用
核心内容:内存原理、索引边界、初始化陷阱、矩阵方阵实战及综合应用
一、 多维数组的定义与内存原理
在一维数组的基础上,当我们需要处理表格、矩阵、多层立体空间(如棋盘、迷宫、多页报表)时,就需要用到二维或三维数组。
1. 二维与三维数组的定义格式
- 二维数组:
数据类型 数组名[行数][列数]; - 示例:
int a[3][4];(定义一个 3 行 4 列的矩阵,共 $3 \times 4 = 12$ 个元素) - 三维数组:
数据类型 数组名[层数][行数][列数]; - 示例:
int b[3][4][5];(定义一个 3 层、每层 4 行 5 列的立体数组,共 $3 \times 4 \times 5 = 60$ 个元素)
2. 内存存储特性(行优先原则)
- 在计算机内存中,多维数组本质上依然是线性连续存储的。
- C++ 采用行优先原则(Row-Major Order):以二维数组为例,它是先存满第 0 行的所有列,再存第 1 行的所有列……以此类推。
二、 数组索引与边界(GESP 核心考点)
在考试中,最容易失分的就是混淆“数组大小”与“合法下标(索引)”。
1. 严格的下标范围规则
C++ 数组下标永远从 0 开始,最大下标是 大小 - 1。
* 对于 int a[3][4];:
* 行下标合法范围:0 ~ 2(共 3 行)
* 列下标合法范围:0 ~ 3(共 4 列)
* ⚠️ 最大合法访问:a[2][3]。若访问 a[3][0] 或 a[2][4] 会造成越界错误(Segmentation Fault)。
* 对于 int b[3][4][5];:
* 层下标合法范围:0 ~ 2
* 行下标合法范围:0 ~ 3
* 列下标合法范围:0 ~ 4
* ⚠️ 最大合法访问:b[2][3][4]。
三、 数组的初始化与“部分初始化陷阱”
在定义数组时进行初始化,如果不完全赋值,会触发 C++ 的默认补零规则。
1. 完全初始化
int a[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
2. 部分初始化(高频考点)
如果初始化时提供的数据少于数组总大小:
* 规则:未被显式赋值的元素,系统会自动补 0。
int b[3][3] = {
{1}, // 第 0 行:b[0][0]=1,其余(b[0][1], b[0][2])自动补 0
{2, 3} // 第 1 行:b[1][0]=2, b[1][1]=3,其余(b[1][2])自动补 0
// 第 2 行:全自动补 0
};
- 全部清零的简写技巧:
cpp int c[3][4] = {0}; // 将二维数组所有元素直接初始化为 0
四、 二维数组的输入输出与双层循环
处理二维数组的核心武器是嵌套循环(外层循环控制行 i,内层循环控制列 j)。
#include <iostream>
using namespace std;
int main() {
int a[3][4];
// 1. 批量读入二维数组
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 4; j++) {
cin >> a[i][j];
}
}
// 2. 以标准矩阵形式输出
cout << "========== 矩阵输出 ==========" << endl;
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 4; j++) {
cout << a[i][j] << "\t"; // 用制表符对齐
}
cout << endl; // 每换一行,输出一个回车
}
return 0;
}
五、 经典实战:数字方阵与规律矩阵
在 GESP 考试中,经常要求输出特定规律的数字方阵。
案例:生成主对角线为 1、其余为 0 的 $N \times N$ 方阵
#include <iostream>
using namespace std;
int main() {
int n = 4;
int matrix[10][10];
// 赋值规律:行号等于列号(i == j)时填 1,否则填 0
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
if(i == j) {
matrix[i][j] = 1;
} else {
matrix[i][j] = 0;
}
}
}
// 打印方阵
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
cout << matrix[i][j] << " ";
}
cout << endl;
}
return 0;
}
六、 专项强化练习题
一、 选择题
1. 设有定义 int a[3][4];,下列关于该数组下标的说法中,正确的是( )
A. 该数组最大的行下标是 3,最大的列下标是 4
B. 该数组合法的行下标范围是 1~3,列下标范围是 1~4
C. 该数组合法的行下标范围是 0~2,列下标范围是 0~3
D. a[3][4] 是该数组中合法的最后一个元素
2. 设有定义 int b[3][4][5];,下列选项中对其元素合法的访问是( )
A. b[3][4][5]
B. b[2][3][4]
C. b[0][4][0]
D. b[1][3][5]
3. 若定义二维数组 int arr[2][3] = {{1, 2}, {3}};,则元素 arr[0][2] 和 arr[1][2] 的值分别是( )
A. 2 和 3
B. 1 和 3
C. 0 和 0
D. 2 和 0
二、 代码阅读与分析题
4. 阅读以下代码片段,写出程序运行后的输出结果:
#include <iostream>
using namespace std;
int main() {
int a[2][3] = { {1, 2}, {3, 4, 5} };
cout << a[0][2] << " " << a[1][1] << " " << a[1][2] << endl;
return 0;
}
参考答案与解析
一、 选择题答案
- C
- 解析:C++ 数组下标一律从
0开始。大小为 3 的行下标是0~2;大小为 4 的列下标是0~3。a[3][4]越界。 - B
- 解析:三维数组各维最大合法下标分别为:层
0~2、行0~3、列0~4。故最大合法访问为b[2][3][4]。 - C
- 解析:第 0 行初始化了
{1, 2},第 3 个元素arr[0][2]未给出,补0;第 1 行初始化了{3, 4, 5},其中第 3 个元素arr[1][2]的值是5。等等,题目中给的是{3, 4, 5},所以arr[1][2]是5,而arr[0][2]是0。因此正确答案为0和5(若选项对应调整)。
二、 代码阅读题答案
- 输出结果:
0 4 5 - 解析:
a[0][2]:第 0 行只给出了{1, 2},第 3 个元素未给出,自动补0。a[1][1]:第 1 行给出了{3, 4, 5},下标1对应的元素是4。a[1][2]:第 1 行下标2对应的元素是5。
—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com