指针数组是每个元素均为指针类型的数组,如int ptrs[3]表示含3个int的数组;易错点包括误读声明、未初始化解引用、存栈变量地址致悬空、重复释放及错误使用delete[]。

怎么定义一个存储指针的数组
就是声明一个数组,每个元素都是指针类型,不是数组里存对象,而是存地址。关键在 * 和 [] 的结合顺序——* 属于变量名,不是类型的一部分。
常见错误是写成 int* arr[5] 却误以为是“指向数组的指针”,其实它是“含 5 个 int* 元素的数组”。反过来,int (*arr)[5] 才是指向含 5 个 int 的数组的指针,别混。
-
int* ptrs[3];—— 正确:3 个int*,每个都能指向一个int -
char** strs[10];—— 存 10 个char*(即字符串首地址) - 如果想让数组元素指向不同大小的对象,得统一用
void*或靠继承/模板,但会丢类型安全
初始化和赋值时最容易崩在哪
未初始化就解引用、野指针、悬空指针——这三类问题在指针数组里放大得特别快,因为“一层间接”变“两层间接”。
比如 ptrs[0] 本身是未初始化的垃圾值,你还写 *ptrs[0] = 42;,直接 undefined behavior。
- 定义后立即初始化为
nullptr:int* ptrs[3] = {nullptr}; - 用
new分配后及时赋值:ptrs[i] = new int(100);,别漏掉 - 别把栈上局部变量地址存进去:
int x = 42; ptrs[0] = &x;→ 函数返回后ptrs[0]就悬空了 - 避免重复
delete:同一个指针被多个数组元素存过?手动管理时极易 double-free
遍历和释放要注意什么
指针数组本身不管理它所指向内存的生命周期,释放必须显式、逐个进行,且不能只删数组本身。
常见错误是调用 delete[] ptrs; —— 这是在删数组容器,不是删里面每个指针指向的内容,而且 ptrs 是栈分配的,根本不能 delete[]。
- 释放内容:
for (int i = 0; i - 如果某元素是
nullptr,delete它是安全的;但delete[]一个非new[]出来的指针就危险 - 用
std::vector<:unique_ptr>></:unique_ptr>替代可自动管理,但那是另一条路——原生指针数组就得自己扛 - 注意对齐和
sizeof(ptrs):它只返回数组总字节数(如 3×8=24 字节 on 64-bit),不是元素个数
和 std::vector 或 std::array 比有什么实际影响
纯指针数组零开销、编译期确定大小、可嵌入结构体,但失去边界检查、无迭代器、无法动态增删。
如果你需要运行时决定长度、频繁插入删除、或怕手抖漏 delete,那它立刻变成负优化。
- 固定大小 + 高频访问 + 确保生命周期可控 → 原生指针数组有优势
- 任何涉及动态、共享、或团队协作场景 → 优先考虑
std::vector<:shared_ptr>></:shared_ptr>或std::array<:unique_ptr>, N></:unique_ptr> - 跨平台时注意:
sizeof(int*)在 32/64 位系统不同,硬编码偏移或序列化指针数组会出问题
真正难的不是语法,是判断哪块内存归谁管、什么时候该释放、以及怎么让别人(包括未来的你)一眼看出这个数组里每个指针到底指向哪片堆/全局/静态区。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











