← 目录 / 第六章 · 数组 / 6.2 二维数组

6.2 二维数组

二维数组像一张表格,有行和列两个维度,适合存储矩阵、棋盘、地图等具有"行列结构"的数据。

二维数组

二维数组像一张表格,有行和列两个维度,适合存储矩阵、棋盘等数据。语法是 类型 数组名[行数][列数];

6.2.1 定义与访问

int matrix[2][3] = { {1,2,3}, {4,5,6} }
行0
1
2
3
行1
4
5
6
列0
列1
列2
matrix[0][1] = 2 ← 第0行第1列
matrix[1][2] = 6 ← 第1行第2列
📖
本质仍是连续内存:二维数组在内存里并不是真的按"表格"排列,而是按行依次首尾相接存放的一维序列——matrix[0][0], matrix[0][1], matrix[0][2], matrix[1][0], ... 依次排开。"行列"只是我们理解数据的方式,底层存储和一维数组一样是连续的。
C++ · 二维数组定义、访问与遍历
1int matrix[2][3] =
2{
3 {1, 2, 3}, // 第0行
4 {4, 5, 6} // 第1行
5};
6
7cout << matrix[0][1]; // 输出:2
8cout << matrix[1][2]; // 输出:6
9
10// 嵌套循环遍历(见 5.3 节)
11for (int i = 0; i < 2; i++) // 遍历行
12{
13 for (int j = 0; j < 3; j++) // 遍历列
14 cout << matrix[i][j] << " ";
15 cout << endl;
16}

6.2.2 初始化方式

二维数组的初始化和一维数组类似,但有一条容易被忽视的规则:第一维(行数)可以省略,第二维(列数)不能省略

C++ · 二维数组的初始化方式
1// 完整初始化
2int a[2][3] = {{1,2,3},{4,5,6}};
3
4// 省略第一维(行数),编译器会自动数一共有几行
5int b[][3] = {{1,2,3},{4,5,6}}; // 自动推断为 2 行
6
7int c[2][] = {{1,2,3},{4,5,6}}; // ❌ 错误!列数不能省略
8
9// 部分初始化,缺省的位置自动补 0
10int d[2][3] = {{1,2}}; // → {{1,2,0},{0,0,0}}
📐
为什么第二维不能省略?回忆 6.1 节的地址计算公式——数组访问依赖"每一行占多少个元素"这个信息来定位。行数只影响"总共分配多大空间",而列数决定了"从第几行开始数",编译器必须知道列数才能正确计算 matrix[i][j] 对应的内存位置,所以列数是不可或缺的。

6.2.3 常见应用:矩阵求和与转置

二维数组最常见的两个基础操作:把所有元素累加求和,以及把矩阵"转置"(行列互换,matrix[i][j] 变成 matrix[j][i])。

C++ · 矩阵求和与转置
1int a[2][3] = {{1,2,3},{4,5,6}};
2
3// ── 求所有元素之和 ──
4int sum = 0;
5for (int i = 0; i < 2; i++)
6 for (int j = 0; j < 3; j++)
7 sum += a[i][j]; // 21
8
9// ── 矩阵转置:行列互换 ──
10int b[3][2]; // 转置后行列大小互换
11for (int i = 0; i < 2; i++)
12 for (int j = 0; j < 3; j++)
13 b[j][i] = a[i][j]; // 行列下标互换写入

6.2.4 常见陷阱与易错点

把本节内容汇总成几条最容易踩坑的规则:

1
行下标和列下标搞反:matrix[i][j]i 是行、j 是列,遍历时如果两层循环的边界写反(比如外层该跑行数却写成列数),要么越界访问,要么漏掉部分数据。养成"外层管行,内层管列"的固定习惯。
2
第二维大小不能省略:只有第一维(行数)可以在初始化时省略让编译器自动推断,第二维(列数)必须显式写明,这是与一维数组初始化最大的区别。
3
大二维数组更容易栈溢出:二维数组的总元素个数是行数乘列数,比如 int a[1000][1000] 就有 100 万个 int,占用约 4 MB,远超局部数组允许的栈空间。这类数组几乎总是需要定义成全局变量。
4
转置时直接在原数组上操作导致数据错乱:如果不使用额外的数组、试图"原地"交换 a[i][j]a[j][i],需要非常小心避免同一对元素被交换两次(抵消效果)或者行列数不相等时下标越界。初学阶段建议像上面的例子一样用一个新数组存放转置结果,逻辑更简单可靠。