因为C++参数传递均为值传递,传入函数的是指针变量所存地址值的副本,修改副本(如p = nullptr)只影响函数栈帧内的形参,不影响调用方指针变量本身;要修改外部指针,须用二级指针或指针引用。

为什么 ptr = nullptr 不影响调用方的指针
因为 C++ 中所有参数传递都是值传递,指针也不例外。传进函数的不是指针本身,而是它存储的那个地址值的拷贝。
比如 int* ptr = &a,ptr 的值是 0x1000;调用 func(ptr) 时,函数形参 int* p 在栈上新开辟空间,把 0x1000 复制进去——p 和 ptr 是两个独立变量,只是值相同、指向同一块内存。
所以:
-
*p = 20→ 修改的是0x1000地址处的值,a变了 ✅ -
p = nullptr→ 只改了栈上那个副本p自己的值,ptr完全没动 ❌
想修改外部指针本身,必须用二级指针或指针引用
如果目标是让调用方的指针变量(比如 ptr)从 nullptr 变成指向新分配的内存,一级指针做不到。
立即学习“C++免费学习笔记(深入)”;
正确做法有两种:
- 用二级指针:
void func(int** pptr),然后*pptr = new int(42)—— 这里解引用一次得到的是ptr的地址,再赋值就真的改了ptr的内容 - 用指针引用:
void func(int*& ptr),然后ptr = new int(42)—— 引用直接绑定到原指针变量,所有操作都作用于本体
错误写法示例:
void bad_alloc(int* p) {
p = new int(42); // 只改了形参 p,main 里的 ptr 仍是 nullptr
}
int main() {
int* ptr = nullptr;
bad_alloc(ptr);
printf("%d", *ptr); // 段错误:ptr 未初始化
}
int* 传参 vs int*& 传参的底层差异
关键不在“能不能改值”,而在于改的是谁的值。
对比内存行为:
-
int* p:函数栈帧里存一个地址值(如0x1000),&p是栈上某个位置(比如0x4000) -
int*& p:函数栈帧里不存地址值,而是存一个“别名绑定”;&p实际就是外部ptr的地址(比如0x3000)
这也解释了为什么引用不能重新绑定:编译器在符号表里把 p 直接映射到 ptr 的地址,没有中间变量可换。
常见误判场景:字符串字面量和指针重绑定
典型坑:char* p = "hello",传入函数后 p = "world",以为外部也变了。
实际发生了什么:
- 原
p存的是"hello"的地址(比如0x5000) - 函数内
p = "world"→ 把形参p改成存0x6000,但外部p仍为0x5000 - 输出还是
"hello",不是"world"
要真正替换,得传 char** 或 char*&,否则只是在函数栈里换了张“纸条”,没动原始“信封”。
真正容易被忽略的点是:指针变量本身也是有地址的,而一级指针参数根本拿不到那个地址。所有试图“让外部指针指向别处”的操作,都必须越过这一层间接性。


















