<p>指针数组声明为int arr[3],是含3个int指针的数组;初始化需用&x取地址或直接赋字符串字面量;传参时勿混淆char*与指针数组,须确保连续内存并显式传长度。</p>

怎么声明和初始化一个指针数组
指针数组本质是「数组」,每个元素都是指针。它解决的是“一堆同类型指针需要批量管理”的问题,比如保存多个字符串首地址、多个对象地址等。
常见错误是写成 int* arr[5] 却当成「指向数组的指针」来用,结果访问越界或解引用失败。
-
int* arr[3]:正确——3 个int*组成的数组,arr[0]是指针,*arr[0]才是 int 值 -
int (*arr)[3]:这是数组指针(指向含 3 个 int 的数组),完全不是一回事 - 初始化时别漏掉取地址:如果想让
arr[0]指向变量x,得写arr[0] = &x,不能写arr[0] = x - 字符串字面量可直接赋:
const char* names[] = {"Alice", "Bob", "Charlie"};——因为字面量在只读区,类型是const char*
为什么 char* str_arr[4] 和 char** p 传参时容易出错
函数参数里写 char** p 看起来能接收指针数组,但实际调用时必须确保内存布局一致:它只认「连续存放的指针」,不检查长度,也不懂你是不是真有一个数组。
典型崩溃场景:把单个 char* 变量的地址传给期望指针数组的函数,比如 func(&s) 传给 void func(char** arr),函数内部却按 arr[1] 访问,立刻越界。
立即学习“C++免费学习笔记(深入)”;
- 安全做法:传指针数组时,显式传长度,例如
process_strings(str_arr, 4) - 函数内别假设
arr后面还有有效指针;每次访问前检查索引是否 len -
std::vector<char></char>或std::vector<:string></:string>更省心,尤其涉及增删时
指针数组和数组指针在 sizeof 和 & 上表现完全不同
这是最常被编译器静默放过的坑:二者类型不同,导致 sizeof 结果差好几倍,取地址运算符 & 的行为也截然不同。
比如 int a[5]; int* p_arr[5]; int (*p_arr2)[5];:
-
sizeof(p_arr)是5 * sizeof(int*)(通常是 40 字节);而sizeof(p_arr2)是sizeof(int[5])(20 字节) -
&p_arr类型是int**[5]的地址?不对——是int* (*)[5];而&p_arr2是int (*(*)[5])[5],极其绕,几乎没人手动写 - 用
auto推导可避开手写类型:auto ptr_to_arr = &p_arr;编译器自己算对
用指针数组管理动态分配的二维数组时,释放内存必须逐层操作
如果你用指针数组模拟二维数组(如 int** mat = new int*[rows]; for(...) mat[i] = new int[cols];),那释放时不能只 delete[] mat ——这只会释放指针数组本身,底下每行堆内存都泄漏了。
- 必须先循环
delete[] mat[i],再delete[] mat - 顺序反了会崩:先
delete[] mat再去delete[] mat[0]就是野指针操作 - 更稳的方式是用
std::vector<:vector>></:vector>,或者单块内存 + 指针数组映射:int* data = new int[rows * cols]; int** mat = new int*[rows]; for(...) mat[i] = data + i * cols;,这样只需两次delete[]
指针数组本身不管理所指内存的生命周期,这点从定义上就决定了——它只是个装地址的盒子,盒子里的纸条撕没撕,得你自己盯紧。









