数组(一维与二维)
本节主线
数组用一个名字保存一批同类数据,用下标找到其中一个。一维数组像一排盒子,二维数组像有行有列的座位表。这节课最终要稳定做到:下标不越界,循环范围与数组范围一致。
先看一个教室座位表
一排 4 名学生的分数可以用 score[j] 保存。如果有 3 排,就需要同时说清“第几排、第几个”,也就是 score[i][j]。
行 i / 列 j | 0 | 1 | 2 | 3 |
|---|---|---|---|---|
| 0 | 86 | 91 | 78 | 95 |
| 1 | 88 | 83 | 90 | 76 |
| 2 | 92 | 85 | 89 | 94 |
例如 score[1][2]=90:第一个下标选行,第二个下标选列。遍历整张表时,外层循环换行,内层循环沿当前行逐列访问。
认知定位
- 建模对象:同类数据组成的序列或方格。
- 算法范式:顺序遍历与模拟。
- 维护信息:数组元素、有效下标范围、当前行列。
- 压缩信息:不再为每个数据单独命名一个变量。
- 学生易卡点:Implementation,容易混淆“元素个数”和“最后下标”。
第一部分:定义数组
int a[5]; // 定义 5 个 int,名字叫 a三个要点:
int是元素类型,a是数组名,5是大小(能装几个)。- 大小必须是整数或整数常量表达式,不能用变量。
- 数组在内存里是连续的一整块。
要用变量般的大小,请用常量:
const int maxn = 1001;
int a[maxn]; // 推荐写法
#define N 1001
int a[N]; // 老式写法,也可以第二部分:下标(索引)
数组用下标访问每个元素,从 0 开始:
int a[5];
a[0] a[1] a[2] a[3] a[4]
a[0]是第 1 个,a[4]是第 5 个(最后一个)。- 竞赛小技巧:把数组开大一点、舍弃
a[0]、从a[1]开始用,这样”a[i]就是第 i 个”,下标和题意对得上,少出错。
⚠️ 下标越界很危险:编译器不检查下标是否有效。写
a[5](越界)能编译通过,但运行时可能破坏别的数据甚至崩溃。开够大小是基本功。
第三部分:初始化
int a[4]; // 不初始化,里面是随机值(垃圾值)
int a[4] = {20, 345, 700, 22}; // 定义同时逐个赋值
int a[10] = {12, 19, 22}; // 只给前 3 个赋值,后 7 个自动补 0
int a[10] = {1}; // 思考:a[0]=1,其余 9 个都是 0!
int a[10] = {0}; // 常用:整个数组清零记住规则:花括号里给了的就用给的值,没给到的一律补 0。
所以{1}不是”全 1”,而是”第一个是 1,其余是 0”。要全 1 只能一个个写。
第四部分:遍历数组(配合循环)
数组和 for 循环是黄金搭档:
int n;
cin >> n;
int a[1005];
for (int i = 1; i <= n; i++) cin >> a[i]; // 读入 n 个数(从 a[1] 开始)
int sum = 0;
for (int i = 1; i <= n; i++) sum += a[i]; // 求和
cout << sum;第五部分:二维数组
存”表格 / 矩阵”这类有行有列的数据:
int g[3][4]; // 3 行 4 列
g[i][j] // 第 i 行、第 j 列遍历要用嵌套循环(呼应循环那一课”外层管行、内层管列”):
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
cin >> g[i][j];
}
}小结
- 数组 = 一排连续的同类型盒子,一个名字 + 下标访问。
- 下标从 0 开始;越界不报错但危险,数组要开够大。
- 初始化规则:没给到的补 0;
{0}清零,{1}只有首位是 1。 - 一维配单层 for,二维配嵌套 for。
课后小练
| 题目 | 练习点 |
|---|---|
| P1427 小鱼的数字游戏 | 一维数组读入与逆序输出 |
| P5731 蛇形方阵 · 题解 | 二维数组、坐标与方向模拟 |
| P5732 杨辉三角 | 二维数组与相邻元素递推 |
衔接:学完数组,下一步常接选择排序等简单排序 —— 见排序专题。