二级指针int pp必须指向已存在的int变量,不可直接指向int;正确步骤为:int a=42; int p=&a; int pp=&p;其核心用途是函数内修改外部指针,需传&pp并用*pp赋值;动态二维数组需先分配指针数组再逐行分配。

二级指针声明和初始化必须匹配层级
声明 int** pp 不是随便多加个 * 就行——它必须指向一个已存在的 int* 变量,不能直接指向 int 或裸地址。常见错误是写成 int** pp = &a(a 是 int),编译器会报错 cannot convert 'int*' to 'int**'。
正确做法分三步:
- 先定义目标变量:
int a = 42; - 再定义一级指针并赋值:
int* p = &a; - 最后用
&取一级指针地址:int** pp = &p;
注意:pp 存的是 p 在栈上的地址,不是 a 的地址;sizeof(pp) 和 sizeof(p) 相同(通常 8 字节),和 sizeof(a) 无关。
函数内修改外部指针必须传二级指针
这是二级指针最不可替代的用途。C++ 函数参数按值传递,传 int* p 进去,函数里改 p = new int(5),调用方的 p 完全不变——因为改的是形参副本。
要让函数真正改变调用方的指针指向,必须传地址:
- 调用方写:
func(&p);(传p的地址) - 函数声明为:
void func(int** pp) - 函数内写:
*pp = new int(5);(解引用一次,改的是原p的值)
漏掉 * 就变成给 pp 本身赋值,不影响外部;多解一次 **pp = 5 是改 a 的值,不是改指针指向。
动态二维数组分配要用二级指针结构
int** arr 常被误认为“就是二维数组”,其实它是“指针数组”:第一层分配 n 个 int*,每层再各自分配一行内存。它不等价于 int arr[3][4](连续内存块)。
典型写法:
-
int** arr = new int*[rows];(分配rows个指针) for (int i = 0; i (每行单独分配)- 访问:
arr[i][j]合法,但底层是两次跳转:先查arr[i]得到某行首地址,再偏移j
释放必须反向:先 delete[] arr[i] 每行,再 delete[] arr 指针数组。漏掉任一环节都会内存泄漏。
二级指针解引用容易空指针崩溃
**pp 实际执行两次内存读取:先读 pp 指向的地址(得 p),再读 p 指向的地址(得 a)。任一层为 nullptr 都会崩。
安全写法必须逐层检查:
- 用前确认:
if (pp != nullptr && *pp != nullptr) - 不能只判
pp,因为*pp可能是野指针或已释放 - 尤其在函数参数中,调用方可能传
nullptr,**pp前不检查等于埋雷
调试时看内存地址链是否断裂比看值更关键——二级指针的问题往往出在中间层断开,而不是最终数据错。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











