共计 1680 个字符,预计需要花费 5 分钟才能阅读完成。
背景痛点
在 C ++ 开发中,指针参数传递是常见的操作,但很多开发者对 *p 和*&p的区别理解不够深入,导致代码中出现以下问题:

- 无效修改:试图通过指针参数修改指针本身(如重新分配内存),但实际未生效。
- 内存泄漏:由于指针传递方式不当,导致内存释放失败或重复释放。
- 野指针:指针被意外修改,指向非法内存区域。
这些问题通常是由于对指针传递的底层机制理解不足导致的。下面我们通过原理对比和代码示例,详细解析两者的区别。
原理对比
*p(值传递指针)
- 底层机制:传递的是指针的拷贝(即指针变量的值,也就是内存地址)。
- 特点:函数内部对指针的修改(如重新赋值)不会影响外部的指针。
- 示意图:
外部指针: 0x1000 -> [数据] 函数内部指针: 0x1000 -> [数据](拷贝的地址)
*&p(引用传递指针)
- 底层机制:传递的是指针的引用(即指针变量本身的引用)。
- 特点:函数内部对指针的修改(如重新赋值)会直接影响外部的指针。
- 示意图:
外部指针: 0x1000 -> [数据] 函数内部指针: 引用 -> 外部指针(同一变量)
代码演示
场景 1:修改指针指向
// 使用 *p(值传递指针)void modifyPointer(int* p) {p = new int(20); // 修改指针指向,但外部指针不受影响
}
// 使用 *&p(引用传递指针)void modifyPointerRef(int*& p) {p = new int(20); // 修改指针指向,外部指针同步修改
}
int main() {int* ptr = new int(10);
modifyPointer(ptr);
// ptr 仍然指向原来的内存(值为 10)modifyPointerRef(ptr);
// ptr 现在指向新的内存(值为 20)delete ptr;
return 0;
}
场景 2:修改指针内容
// 使用 *p(值传递指针)void modifyContent(int* p) {*p = 30; // 修改指针指向的内容,外部数据同步修改}
// 使用 *&p(引用传递指针)void modifyContentRef(int*& p) {*p = 40; // 修改指针指向的内容,外部数据同步修改}
int main() {int* ptr = new int(10);
modifyContent(ptr);
// *ptr 现在是 30
modifyContentRef(ptr);
// *ptr 现在是 40
delete ptr;
return 0;
}
场景 3:多级指针操作
// 使用 *p(值传递指针)void modifyMultiLevel(int** p) {*p = new int(50); // 修改二级指针指向的内容,外部数据同步修改
}
// 使用 *&p(引用传递指针)void modifyMultiLevelRef(int**& p) {*p = new int(60); // 修改二级指针指向的内容,外部数据同步修改
}
int main() {int* ptr = new int(10);
int** ptrPtr = &ptr;
modifyMultiLevel(ptrPtr);
// *ptr 现在是 50
modifyMultiLevelRef(ptrPtr);
// *ptr 现在是 60
delete ptr;
return 0;
}
避坑指南
- 明确需求:如果需要修改指针本身(如重新分配内存),使用
*&p;如果只需要修改指针指向的内容,使用*p。 - const 修饰 :如果函数不需要修改指针或内容,使用
const修饰(如const int* p或const int*& p)。 - 内存管理:确保在函数内外对内存的分配和释放保持一致,避免内存泄漏或重复释放。
- 多线程安全:在多线程环境下,避免直接传递裸指针,考虑使用智能指针或加锁机制。
- 代码注释:在复杂场景下,务必添加注释说明指针参数的传递方式和预期行为。
延伸思考
- 智能指针场景 :在 C ++11 及以上版本中,如何使用
std::shared_ptr或std::unique_ptr替代裸指针,避免*p和*&p的混淆? - 性能考量 :
*&p相比*p是否会带来额外的性能开销?在什么场景下这种开销可以忽略不计?
希望通过本文的解析,你能更好地理解 *p 和*&p的区别,并在实际开发中避免常见的指针误用问题。
正文完
