std::array 与 C 数组
更新时间:2026-08-27。本文是
languages/cpp/主题入门层第 34 篇。大小编译期固定的数组,C++ 给了它一个正名:std::array——有size()、有边界检查、能传给函数不退化,而且零额外开销。C 数组的"传参退化成指针"老大难问题,它直接根治。
本文要回答的问题
- C 数组传参为什么会"退化"成指针?有多坑?
std::array解决了什么?std::array和vector怎么选?
一、C 数组的老大难:传参退化
c
void process(int arr[], int n) { // arr[] 其实退化成 int*
// ...
}
int data[10];
process(data, 10); // 要手传长度C 里数组作为函数参数时退化成指针:int arr[] 等价 int* arr,长度信息丢失。于是每个 C 函数都得额外带一个长度参数,还得指望调用方传对。忘了长度、传错长度、越界写——C 数组三件套。
更隐蔽的是:
c
int data[10];
printf("%zu\n", sizeof(data)); // 40:在定义处,sizeof 是整个数组
printf("%zu\n", sizeof(f(data))); // 不可能,长度早没了sizeof 只能在数组定义处得到正确大小,一旦传给函数,sizeof(arr) 就是 8(指针大小)了。
二、std::array:带大小的固定数组
cpp
#include <array>
std::array<int, 10> data; // 类型里直接写大小
data.size(); // 10,随时可查
std::array<int, 5> a = {1, 2, 3, 4, 5};
a[0]; // O(1) 访问
a.at(0); // 带边界检查
void process(const std::array<int, 10>& data) {
// 长度是类型的一部分,不会丢
for (int x : data) { /* ... */ }
}三个关键点:
- 大小是类型的一部分:
std::array<int, 10>和std::array<int, 20>是两个不同类型,传参时类型自带长度,不会退化; - 有
size()、at()、范围 for:迭代器和算法库直接能用(第 38/39 篇),C 数组做不了; - 零额外开销:底层就是裸数组,布局完全一样,没有堆分配、没有虚函数——编译器能把它优化成和内建数组一样。
三、和 C 数组对比
| 对比项 | C 数组 | std::array |
|---|---|---|
| 长度 | 传参丢失,sizeof 不可靠 | .size(),类型自带 |
| 边界检查 | 无 | .at() 抛异常 |
| 传给函数 | 退化成指针 + 手传长度 | 直接传引用 |
| 算法库 | 不能直接用 | sort/find 通用 |
| 额外开销 | 无 | 无(零开销抽象) |
| 初始化 | {1,2,3} | {1,2,3} 一样 |
表格最后一行值得强调:std::array 是 C++ 设计"零开销抽象"的典型代表——功能增加了,代价为零。内存布局、访问速度跟 C 数组一模一样。
四、std::array vs vector
std::array | std::vector | |
|---|---|---|
| 大小 | 编译期固定 | 运行期动态 |
| 内存 | 栈上(作为局部变量时) | 堆上 |
| 扩容 | 不可能 | 自动 |
| 适用 | 大小已知且固定 | 大小可变或不确定 |
| 性能 | 无分配开销 | 可能有扩容开销 |
cpp
std::array<int, 3> a = {1, 2, 3}; // 固定 3 个,用 array
std::vector<int> v; // 个数不确定,用 vector选择很简单:大小编译期就定死 → std::array;大小运行期才知道/会变 → vector。两者遍历都缓存友好(连续内存),array 因为免堆分配,在嵌入式、高频小场景更有优势。
五、多维度数组
cpp
std::array<std::array<int, 3>, 3> grid{}; // 3×3 二维数组
// 遍历
for (const auto& row : grid) {
for (int x : row) { /* ... */ }
}二维数组用嵌套 std::array 表达,遍历靠范围 for 直接展开,比 C 的 int grid[3][3] + 双重下标清晰得多(底层内存仍然连续)。
六、与本站主线衔接
- 数组在内存里的连续布局与缓存局部性,见 L3 缓存与局部性;
- 数组越界是未定义行为的重灾区,见 C 数组越界与边界检查(原理互通);
- 下一篇:
list/deque——连续数组之外的顺序容器。
一句话总结
std::array<int, N> 是带大小信息的固定数组:.size() 随时可查、传参不退化、支持 .at() 边界检查和算法库,且零额外开销(底层就是裸数组);C 数组传参退化成指针、长度靠手传的老大难被它根治;大小编译期固定用 array,动态变化用 vector。
上一篇:string 深入 下一篇:list / deque