目录
[3.1 数组的本质](#3.1 数组的本质)
[3.2 数组为什么访问快](#3.2 数组为什么访问快)
[3.3 数组变量的本质](#3.3 数组变量的本质)
[4.1 栈区数组](#4.1 栈区数组)
[4.2 堆区数组](#4.2 堆区数组)
[4.3 vector(容器数组)](#4.3 vector(容器数组))
[(3)vector 的内存结构](#(3)vector 的内存结构)
[(4)vector 的核心优势](#(4)vector 的核心优势)
[4.4 三种数组的核心对比](#4.4 三种数组的核心对比)
[五、数组 vs vector 对比](#五、数组 vs vector 对比)
[6.1 栈区数组(局部数组)](#6.1 栈区数组(局部数组))
[6.2 堆区数组(动态分配数组)](#6.2 堆区数组(动态分配数组))
[6.3 总结](#6.3 总结)
[7.1 数组核心](#7.1 数组核心)
[7.2 三种数组](#7.2 三种数组)
[7.3 一句话总结](#7.3 一句话总结)
一、本节学习内容概要图


二、前言
在前面的内容中,我们已经学习了:
- 变量与基本类型
- if / switch 条件控制
- for / while 循环控制
但在实际开发中,仅仅会"控制流程"是不够的,我们还需要解决一个更核心的问题:
👉 数据如何存储?
例如:
- 一批图片数据如何存储?
- 一组路径点如何管理?
- 多个传感器数据如何统一处理?
- 大量计算结果如何高效访问?
这些问题,本质上都离不开一种结构:
数组(Array)与容器(Container)
在 C++ 中,我们最常用的就是:
- 数组(Array)
- vector(动态数组)
这一节,我们不只是学"怎么用",更重要的是:
👉 搞清楚它们的底层本质和内存结构
三、数组是什么
3.1 数组的本质
数组本质上是:
一段连续的内存空间
例如:
cpp
int arr[5] = {1,2,3,4,5};
在内存中可以理解为:(int 4个字节)
cpp
地址: 1000 1004 1008 1012 1016
数据: 1 2 3 4 5
👉 这里有几个非常关键的点:
- 每个元素紧挨着存储(连续)
- 每个元素类型相同(int)
- 每个元素占用固定字节数(4字节)
3.2 数组为什么访问快
我们来看最常见的访问方式:
cpp
arr[3];
(1)访问值的本质
这句代码本质上做的事情是:
首地址 + 下标 × 元素大小
等价写法:
cpp
*(arr + 3);
👉 逐步拆解理解
arr→ 数组首地址arr + 3→ 第 4 个元素的地址*(arr + 3)→ 取该地址中的值
✅ 访问值总结
| 写法 | 含义 |
|---|---|
| arr[3] | 访问第4个元素的值 |
| *(arr + 3) | 访问第4个元素的值 |
(2)访问地址
如果我们想要"地址",就要这样写:
cpp
&arr[3];
等价:
cpp
arr + 3;
✅ 地址 vs 值对比(重点)
| 表达式 | 类型 | 含义 |
|---|---|---|
| arr | int* | 首地址 |
| arr + 3 | int* | 第4个元素地址 |
| &arr[3] | int* | 第4个元素地址 |
| *(arr + 3) | int | 第4个元素的值 |
| arr[3] | int | 第4个元素的值 |
👉 为什么数组访问这么快?
因为 CPU 只需要:
- 一次地址计算(偏移)
- 一次内存读取
👉 不需要查表、不需要跳转
👉 时间复杂度:O(1)
✅ 一句话总结
arr + i 是地址,*(arr + i) 才是值
3.3 数组变量的本质
cpp
int arr[5];
👉 这里最关键的一点是:
arr 本质上表示这段连续内存的"首地址"
(1)可以这样理解
cpp
int* p = arr;
👉 完全等价成立
说明:
- arr 可以当作一个指针使用
- 指向数组的第一个元素
(2)一个关键区别
👉 arr 不是指针变量
而是:
数组名在大多数表达式中会"退化"为指针"
(3)简单例子对比
cpp
int arr[5];
int* p = arr;
| 名称 | 本质 |
|---|---|
| arr | 数组名(固定地址) |
| p | 指针变量(可以改变指向) |
👉 关键区别
cpp
p = p + 1; // ✅ 可以
arr = arr + 1; // ❌ 错误(数组名不能修改)
四、C++中的数组分类
在 C++ 中,数组并不只有一种形式。根据内存分配方式和管理方式的不同,通常可以分为三类:
- 栈区数组(Stack Array)
- 堆区数组(Heap Array)
- vector(动态数组容器)
这三者的核心区别,本质上是:
内存在哪分配?谁来管理?是否可扩展?
4.1 栈区数组

(1)定义方式
cpp
int arr[10];
string strs[10];
char str[10];
数组 = 类型 + 数量
👉 这种数组:
- 定义在函数内部
- 内存分配在栈区
- 由系统自动管理
(2)生命周期
cpp
void func()
{
int arr[5];
}
👉 执行过程:
- 进入函数 → 分配内存
- 离开函数 → 自动释放
(3)空间大小申请
👉 通过 [] 控制:
cpp
int arr[10];
👉 关键点(你图里的重点):
✅ 必须是编译期常量(constexpr)
❌ 不支持:
cpp
int n = 10;
int arr[n]; // ❌ 标准C++不支持(GCC扩展除外)
(4)空间大小计算
cpp
sizeof(arr);
👉 作用:
返回整个数组占用的字节数
例如:
cpp
int arr[10];
cout << sizeof(arr); // 40
(5)栈区特点
- 内存从高地址向低地址增长
- 分配速度非常快(几乎是指令级)
- 不需要程序员管理
(6)优缺点
✅ 优点:
- 访问速度快
- 自动释放(安全)
- 使用简单
❌ 缺点:
- 空间有限(容易栈溢出)
- 大小必须固定
4.2 堆区数组

(1)基本定义
cpp
int* arr = new int[5];
或者:
cpp
auto arr3 = new char[4];
👉 这种数组:
- 分配在堆区
- 由程序员手动管理
(2)内存释放
cpp
delete[] arr2;
delete[] arr3;
👉 如果不释放:
❌ 会发生内存泄漏
(3)生命周期
- 不受作用域限制
- 只要不 delete,就一直存在
(4)堆区特点
- 内存从低地址向高地址增长
- 空间较大
- 分配速度比栈慢(涉及系统管理)
(5)优缺点
✅ 优点:
- 支持动态分配(运行时决定大小)
- 生命周期灵活
❌ 缺点:
- 需要手动释放
- 容易内存泄漏
- 使用复杂
4.3 vector(容器数组)

(1)头文件与命名空间
cpp
#include <vector>
std::vector<int> v;
👉 vector 是:
C++ STL 提供的动态数组容器
可以理解为:
👉 "自动管理的堆数组 + 更安全的接口"
(2)vector语法本质
cpp
vector<元素类型> 变量名(初始数量);
例如:
cpp
vector<int> v(10);
(3)vector 的内存结构
vector 的结构其实是"栈 + 堆"的结合:
栈区:
v(内部包含:指针 + size + capacity)
堆区:
实际存储的数据(连续空间)
👉 说明:
- v 这个变量本身在栈上
- 数据在堆上
(4)vector 的核心优势
相比普通数组:
✅ 自动扩容(不用关心大小)
✅ 自动释放(避免内存泄漏)
✅ 提供丰富操作接口
(5)常用操作示例
cpp
v.push_back(10); // 末尾插入
v.erase(v.begin()); // 删除第一个元素
(6)迭代器访问
cpp
for (auto it = v.begin(); it != v.end(); ++it)
{
cout << *it;
}
4.4 三种数组的核心对比
| 特性 | 栈区数组 | 堆区数组 | vector |
|---|---|---|---|
| 内存位置 | 栈 | 堆 | 栈 + 堆 |
| 生命周期 | 自动 | 手动 | 自动 |
| 大小 | 固定 | 可变 | 可变 |
| 安全性 | 高 | 低 | 高 |
| 使用难度 | 简单 | 较复杂 | 简单 |
| 是否推荐 | 小数据 | 特殊场景 | ⭐工程首选 |
五、数组 vs vector 对比
| 特性 | 数组 | vector |
|---|---|---|
| 内存 | 连续 | 连续 |
| 大小 | 固定 | 可变 |
| 管理 | 手动 | 自动 |
| 安全性 | 低 | 高 |
六、初始化是否为0
6.1 栈区数组(局部数组)
cpp
int arr[5]; // 局部变量
-
特点:存储在栈上,通常是函数内部定义的局部变量。
-
默认值:不初始化的话,内容是随机的(垃圾值),不会自动变成 0。
-
初始化为 0 的方法:
cppint arr[5] = {}; // 所有元素自动初始化为 0 int arr[5] = {0}; // 同样效果
6.2 堆区数组(动态分配数组)
cpp
int* arr = new int[5]; // 动态分配
int* arr2 = new int[5]{}; // 带括号的动态分配
- 特点 :存储在堆上,通过
new或malloc分配。 - 默认值 :
new int[5]→ 不初始化,内容是随机的(垃圾值)new int[5]{}→ 初始化为 0
6.3 总结
| 类型 | 初始化方式 | 默认值 |
|---|---|---|
| 栈区数组 | int a[5]; |
随机值 |
| 栈区数组 | int a[5] = {}; |
0 |
| 堆区数组 | new int[5]; |
随机值 |
| 堆区数组 | new int[5]{}; |
0 |
简单记忆口诀:
局部不赋值 → 垃圾值;全局或静态 → 自动 0;new() → 可以选择初始化 0
七、本节总结
7.1 数组核心
- 连续内存
- O(1)访问
- arr 是首地址
7.2 三种数组
| 类型 | 特点 |
|---|---|
| 栈数组 | 自动释放 |
| 堆数组 | 手动管理 |
| vector | 自动+动态 |
7.3 一句话总结
👉 数组 = 性能极致但不灵活
👉 vector = 工程首选容器