二维数组的初始化有两种写法:分行写({{1,2,3},{4,5,6}},看得清每行)和不分行写({1,2,3,4,5,6},按行优先顺序一路填下去)。没写满的格子仍然自动补 0,= {} 依然是把整张表刷 0 的最短写法。唯一的硬规矩:列数不能省,行数可以。
上一节讲"怎么取一格",这一节讲"怎么把整张表一次摆好"。规则是 7.1.3 那一套的直接推广:花括号、自动补 0、{} 清零——只是多了一层嵌套。"分行"与"不分行"的等价性,靠的正是 7.2.1 讲的行优先布局:不分行写法就是"把行优先那一排原样抄下来"。
一、写法 1:分行写(推荐)
int a[3][4] = {
{85, 92, 78, 90}, // 第 0 行
{60, 75, 88, 95}, // 第 1 行
{100, 55, 70, 80} // 第 2 行
};
外层一对花括号包住整张表,里层每对花括号包住一行。好处是看得见行——哪几个数是一行的,一目了然。写成绩表、矩阵都推荐这种。
二、写法 2:不分行写(按行优先铺开)
int b[3][4] = {85, 92, 78, 90, 60, 75, 88, 95, 100, 55, 70, 80};
效果和上面完全一样。因为它就是按 7.2.1 的内存顺序一路填:第 0 行 4 格 → 第 1 行 4 格 → 第 2 行 4 格。
缺点很明显:一眼看不出哪几个数是一行。只适合给很短的、或全 0 的表用。超过一行的数据,尽量分行写。
三、写法 3:填一部分,其余补 0
在"分行"的基础上,每行也可以只写一部分:
int c[3][4] = {
{1}, // {1, 0, 0, 0}
{4, 5}, // {4, 5, 0, 0}
{7, 8, 9} // {7, 8, 9, 0}
};
每一行没写完的格子补 0,而不是"补下一行的数"。这一点和"不分行只写一半"不一样:
int d[3][4] = {1, 2, 3}; // {1,2,3,0, 0,0,0,0, 0,0,0,0}
// 前三个数全在第 0 行!
这是本节最容易搞错的一处:不分行时,没写的数不会自动分给第 1、2 行,整张表在第 0 行就被填了 3 格,后面 9 格全是 0。
四、写法 4:整张表清零
int e[3][4] = {}; // 整张表 12 格全 0
char g[19][19] = {}; // 围棋盘全空
和 7.1.3 一样,空花括号 = 全刷 0,不是"什么都不做"。这是最常用的"开局清干净"写法。
五、行数可省、列数不可省
int f[][4] = {{1,2,3,4}, {5,6,7,8}}; // ✅ 行数自动算出 2
int h[3][] = {{1,2,3,4}, {5,6,7,8}}; // ❌ 列数不能省,编译报错
为什么列数不能少?因为编译器必须知道"一行有多长"(就是 7.2.1 的"每行 16 字节"),才能算出 a[i][j] 到底在哪儿;行数则可以从花括号数据里数出来。
六、动手 Demo:四种形态对照
#include <iostream>
using namespace std;
void print2D(int a[][4], int rows) { // 列数不能省,7.8.3 详解
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 4; j++) cout << a[i][j] << "\t";
cout << endl;
}
cout << endl;
}
int main() {
int a[3][4] = {{85,92,78,90},{60,75,88,95},{100,55,70,80}};
int b[3][4] = {1, 2, 3};
int c[3][4] = {{1},{4,5},{7,8,9}};
int d[3][4] = {};
cout << "分行全填:" << endl; print2D(a, 3);
cout << "不分行填三个:" << endl; print2D(b, 3);
cout << "分行各填一部分:" << endl; print2D(c, 3);
cout << "空花括号:" << endl; print2D(d, 3);
return 0;
}
看到什么算成功:
分行全填:
85 92 78 90
60 75 88 95
100 55 70 80
不分行填三个:
1 2 3 0
0 0 0 0
0 0 0 0
分行各填一部分:
1 0 0 0
4 5 0 0
7 8 9 0
空花括号:
0 0 0 0
0 0 0 0
0 0 0 0
重点看第二块:{1,2,3} 全落在第 0 行,其余 9 格是 0。第三块则每行各留了点 0——"分行"和"不分行"的差别,全在这里。
30 秒实验:把 int b[3][4] = {1, 2, 3}; 改成 int b[3][4] = {1, 2, 3, 4, 5};,重跑第二块——变成第 0 行 1 2 3 4、第 1 行第 0 列 5、其余全 0。自己顺着"行优先"数一遍,就能彻底记住这个规矩。
七、常见误区
- "不分行只写三个数,会一行分一个"——不会。从头按行优先一路填,前三个全在第 0 行。
- "分行写时,某行不写满会接着填下一行"——不会。每行各自补 0,行与行之间互不影响。
- "行数列数都能省"——只有行数能省(
a[][4])。列数必须写,因为它决定"一行多长"。 - "
= {}是没初始化"——是全部置 0。不初始化是int a[3][4];(垃圾值),两者完全不同。 - "花括号的层数无所谓"——层数对了才是"分行"。少写一层勉强能编过(就是不分行写法),但含义会变。
自测三问(点开对答案)
1. `int a[3][4] = {1, 2};` 之后 `a[1][0]` 是几?——`0`。两个数都在第 0 行,其余全补 0。 2. `int a[][4] = {{1,2,3,4},{5,6,7,8}};` 合法吗?——合法,**行数自动算出 2**。但列数 `4` 不能省。 3. 把 3×4 数组整张清零的最短写法?——`int a[3][4] = {};`- ☐ 7.3 字符数组(下一节)
相关笔记
- 二维数组的声明 —— "行优先"是这里的根据
- 一维数组的初始化 —— 花括号规则的来源
- 二维数组元素的引用 —— 打印表格的两层循环
- 🔷 C++基础 · 索引 —— 全课路线图