指针数组声明为int arr[5],表示含5个int元素的数组;易与数组指针int (arr)[5]混淆;需显式初始化为nullptr或地址,访问时需双重解引用arr[i]。

指针数组的声明语法容易写反
很多人把 int* arr[5] 误写成 int *arr[5](空格位置无关,关键在 * 和 [5] 的相对顺序),或更常见的是和「数组指针」混淆写成 int (*arr)[5]。前者是「含 5 个 int* 元素的数组」,后者是指向「含 5 个 int 的数组」的单个指针——完全不是一回事。
记住口诀:方括号 [] 紧贴变量名,* 贴类型或变量名都行,但优先级上 [] 高于 *,所以 int* arr[5] 解析为 (int*) arr[5],即数组,每个元素是 int*。
-
int* arr[3];—— 正确:3 个指向int的指针组成的数组 -
int (*p)[3];—— 错误目标:这是指向「长度为 3 的 int 数组」的指针,不是指针数组 - 声明后必须初始化或赋值,否则每个指针都是野指针(值未定义)
初始化指针数组的三种常见方式
不能像普通数组那样用 {1,2,3} 直接初始化指针数组,因为花括号里填的是整数,不是地址。必须显式提供地址或 nullptr。
- 全部初始化为
nullptr:int* arr[4] = {nullptr, nullptr, nullptr, nullptr};或简写为int* arr[4] = {};(C++11 起,零初始化) - 指向已有变量:
int a=1,b=2,c=3; int* arr[3] = {&a, &b, &c}; - 指向堆内存:
int* arr[2]; arr[0] = new int(10); arr[1] = new int(20);(记得配对delete)
注意:如果用 new int[5] 分配一整块内存,再让某个指针元素指向它,没问题;但别试图用 int* arr[3] = {new int[5], new int[5], new int[5]}; —— 编译能过,但后续释放时容易漏掉或重复 delete[]。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
访问和解引用要多写一层 *
指针数组本质是「数组」,它的每个元素本身是个指针,所以访问值需要两次解引用:arr[i] 是指针,*arr[i] 才是它指向的 int 值。
- 错误写法:
cout → 输出地址(可能被当整数打印) - 正确写法:
cout → 输出该指针所指的值 - 如果指针为空:
if (arr[0]) cout ,否则解引用会崩溃 - 和二维数组不同:指针数组不要求所有指针指向相同大小的内存,
arr[0]可以指向单个int,arr[1]指向new int[10]
和 std::vector<:unique_ptr>></:unique_ptr> 的取舍
纯 C 风格的指针数组在现代 C++ 中往往不是首选,尤其涉及动态内存管理时。手动管理 new/delete 容易出错,且无法自动随作用域销毁。
- 替代方案:
std::vector<:unique_ptr>> ptrs(5);</:unique_ptr>—— 自动管理内存,支持动态增删 - 如果需要固定大小且不打算增删,
std::array<:unique_ptr>, 5> arr;</:unique_ptr>更安全 - 只有在对接 C API、性能极致敏感、或明确要求栈上分配固定大小指针容器时,才用原生指针数组
- 混用风险:把
int* arr[5]传给期望int**的函数没问题(数组名退化为指针),但传给期望int(*)[5]的函数就类型不匹配
真正麻烦的从来不是怎么写出来,而是后续谁负责释放、哪些指针可能为空、有没有越界访问——这些不会在声明那一行报错,却会在运行时咬你一口。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










