C++函数调用中指针参数*p与*&p的深度解析与避坑指南

1次阅读
没有评论

共计 1680 个字符,预计需要花费 5 分钟才能阅读完成。

image.webp

背景痛点

在 C ++ 开发中,指针参数传递是常见的操作,但很多开发者对 *p 和*&p的区别理解不够深入,导致代码中出现以下问题:

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;
}

避坑指南

  1. 明确需求:如果需要修改指针本身(如重新分配内存),使用*&p;如果只需要修改指针指向的内容,使用*p。
  2. const 修饰 :如果函数不需要修改指针或内容,使用const 修饰(如 const int* p 或const int*& p)。
  3. 内存管理:确保在函数内外对内存的分配和释放保持一致,避免内存泄漏或重复释放。
  4. 多线程安全:在多线程环境下,避免直接传递裸指针,考虑使用智能指针或加锁机制。
  5. 代码注释:在复杂场景下,务必添加注释说明指针参数的传递方式和预期行为。

延伸思考

  1. 智能指针场景 :在 C ++11 及以上版本中,如何使用std::shared_ptr 或std::unique_ptr替代裸指针,避免 *p 和*&p的混淆?
  2. 性能考量 :*&p 相比 *p 是否会带来额外的性能开销?在什么场景下这种开销可以忽略不计?

希望通过本文的解析,你能更好地理解 *p 和*&p的区别,并在实际开发中避免常见的指针误用问题。

正文完
 0
评论(没有评论)