📄 一句话概括
数组=同类型数据排成一排连续存放、按下标直达——下标从 0 起,因为它是【偏离起点的格数】。
📝 本节和前面几节的关系
格子关系焊牢了,第一种数据结构登场:数组——最常用、也几乎是一切其他结构的舞台。
一、数组的三个特征
同类型:每格装的东西一样大(都是 int、都是 char);
连续存放:在内存里一格贴一格,不留缝;
按下标访问:scores[2] 一步直达,不用从头数。
三个特征是一体的:正因为同类型等大+连续,地址才能用公式算——起点地址+下标×格子大小,一步跳到任意格。
二、下标为什么从 0 开始
初学最别扭的一件事。原因就藏在地址公式里:下标其实是【偏离起点的格数】——第 1 格偏移 0 格、第 2 格偏移 1 格。 从 0 数起,地址公式最简洁;从 1 数起反而要处处减一。语言设计者选了让机器省事的那种。
三、越界:数组的规矩
5 格的数组最大下标是 4——访问下标 5 就是越界。 有的语言会报错拦下(Python 的 IndexError),C 语言不拦、直接读写隔壁格子——缓冲区溢出这个经典安全漏洞就是这么来的(19 课信息安全课的主角之一)。
四、动手 Demo:数组的下标与越界
建一个 5 格数组,走一遍按下标读写、再故意越界看报错。
# 数组(Python 里用列表演示)
scores = [88, 92, 79, 95, 83]
print(scores[2]) # 下标 2 -> 第 3 格
scores[0] = 90 # 按下标改值
print(scores)
print(scores[5]) # 越界!
实跑输出:
--------------------------------------------------------------------
要点 2——数组:排成一排的同类型格子
--------------------------------------------------------------------
数组三个特征:**同类型**、**连续存放**、**按下标访问**(下标从 0 起)。
一个 5 格的 int 数组:
下标 0 <- 值 88
下标 1 <- 值 92
下标 2 <- 值 79
下标 3 <- 值 95
下标 4 <- 值 83
按下标取值: scores[2] = 79 (第 3 格, 因为从 0 数起)
按下标改值: scores[0] = 90 后 -> [90, 92, 79, 95, 83]
[重要规矩] 越界会出事:
访问 scores[5] -> 报错 IndexError! (最大下标只有 4)
特征 好处 代价
--------------------------------------------------------------
连续存放 按下标一步跳到任意格 中间插队要整体挪
同类型 每格一样大, 好算地址 想混装就得用结构体(6.6)
为什么下标从 0 开始?——下标其实是【偏离起点的格数】:
第 1 格偏移 0 格, 第 2 格偏移 1 格……数组地址 = 起点地址 + 下标 x 格子大小。
报错信息 IndexError 就是在提醒【你的下标出了界】——读报错先看下标值。 【⚠️ 2026 现状】Python 的列表其实比 C 数组更高级(可混装、可变长),但下标从 0、按位直达这两个核心行为一脉相承。
30 秒实验
- 心算:int 数组每格 4 字节、起点地址 1000,下标 6 的地址是多少?(1024)
- 故意写一个越界访问,读一遍报错信息——习惯从报错定位下标错误。
常见误区
- 以为 5 格数组的最后一个是下标 5——是 4,从 0 数起。
- 以为越界顶多读到垃圾值——在 C 语言里它是严重安全漏洞的入口。
自测三问(点开对答案)
1. 数组的三个特征? —— 同类型、连续存放、按下标访问。 2. 下标为什么从 0 开始? —— 下标=偏离起点的格数,地址公式(起点+下标×格大小)最简洁。 3. 缓冲区溢出与数组什么关系? —— 越界写数组却不被拦截(如 C 语言),就会覆盖相邻内存——安全漏洞的经典来源。- ☐ 下一节(6.3 要点3:了解数组的应用——作为典型算法的数据结构)
相关笔记
- Z80 CPU 的寄存器结构 — 内存格子与寄存器,第三章就打过照面
- 🛡️ 网络与信息安全 · 索引 — 缓冲区溢出攻击在那边登场
- 💻 计算机是怎样跑起来的 · 索引