c++ 函数参数传递

C++ 中的值传递和地址传递

在 C++ 中,函数参数传递主要有两种方式:值传递地址传递(指针传递和引用传递都属于地址传递的变体)。

1. 值传递

特点

  • 函数接收的是实参的副本
  • 对形参的修改不会影响原始变量
  • 适用于小型数据(基本类型、小型结构体)
void increment(int x) {
    x++;  // 只修改局部副本
}

int main() {
    int a = 5;
    increment(a);
    cout << a;  // 输出 5,原始值未改变
    return 0;
}

值传递优缺点

优点

  • 安全,原始数据不会被意外修改
  • 实现简单直观

缺点

  • 对于大型对象,复制开销大
  • 无法通过参数返回修改结果

2. 地址传递

2.1 指针传递

void increment(int* x) {
    (*x)++;  // 解引用并修改原始值
}

int main() {
    int a = 5;
    increment(&a);  // 传递地址
    cout << a;      // 输出 6,原始值被修改
    return 0;
}

2.2 引用传递

void increment(int& x) {
    x++;  // 直接修改原始值
}

int main() {
    int a = 5;
    increment(a);  // 看起来像值传递,实际是引用传递
    cout << a;     // 输出 6
    return 0;
}

地址传递的优缺点

优点

  • 避免大型对象的复制开销(减少内存拷贝,提升性能)
  • 可以在函数中修改实参的值
#include <iostream>
using namespace std;

void func(int a, int b, int c, int* max, int* min)
{
    // 先假设a是最大值,b是最小值
    *max = a;
    *min = b;
    
    if (b > a) {
        *max = b;
        *min = a;
    }
    
    // 检查c是否比当前最大值大
    if (c > *max) {
        *max = c;
    }
    // 检查c是否比当前最小值小
    else if (c < *min) {
        *min = c;
    }
}

int main()
{
    int a = 5;
    int b = 8;
    int c = 1;
    int max, min;  // 声明max和min变量
    
    func(a, b, c, &max, &min);  // 传递max和min的地址
    
    cout << "max = " << max << ", " << "min = " << min << endl;
    
    return 0;
}

缺点

  • 可能意外修改原始数据(指针传递)
  • 指针可能为 nullptr(需要检查)
  • 引用不能重新绑定(有时是优点)

3. 对比表格

特性值传递指针传递引用传递
传递内容值的副本内存地址别名(隐式指针)
语法func(int x)func(int* x)func(int& x)
调用方式func(a)func(&a)func(a)
修改原始值不能
空值检查不需要需要不需要
性能小型数据高效大型数据高效大型数据高效
安全性中(可能空指针)
可读性直观需要理解指针直观

4. 现代C++最佳实践

  • 优先使用const引用传递大型只读对象
void printBigObject(const BigObject& obj);
  • 使用智能指针代替裸指针进行资源管理
void process(std::shared_ptr<Resource> res);

5. 示例:三种方式实现swap函数

// 值传递(无法实现swap)
void swap_fail(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}

// 指针传递
void swap_ptr(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// 引用传递(推荐)
void swap_ref(int& a, int& b) {
    int temp = a;
    a = b;
    b = temp;
}

int main() {
    int x = 1, y = 2;
    
    swap_fail(x, y);
    cout << x << " " << y;  // 1 2(未交换)
    
    swap_ptr(&x, &y);
    cout << x << " " << y;  // 2 1(已交换)
    
    swap_ref(x, y);
    cout << x << " " << y;  // 1 2(再次交换)
    
    return 0;
}

为什么函数内部不能直接修改指针本身

在 C++ 中,函数参数传递默认是值传递,包括指针参数。

1. 指针参数的本质

当你传递指针给函数时:

void func(int* ptr) {
    ptr = new int(10);  // 这只会修改局部副本
}

int main() {
    int* p = nullptr;
    func(p);
    // p 仍然是 nullptr!
}

这是因为:

  • 函数接收到的是指针的副本(指针值的拷贝)
  • 修改这个副本(ptr = ...)不会影响原始指针
  • 这就像值传递一个 int 参数一样

2. 可以修改指针指向的内容

虽然不能直接修改指针本身,但可以修改指针指向的内容

void modifyContent(int* ptr) {
    *ptr = 10;  // 这会修改指针指向的内存
}

int main() {
    int x = 5;
    int* p = &x;
    modifyContent(p);
    // x 现在是 10
}

3. 如何真正修改指针本身

如果需要修改指针本身(而不仅是指向的内容),你需要:

方法1:使用指针的指针(二级指针)

void modifyPointer(int** ptrPtr) {
    *ptrPtr = new int(20);  // 修改原始指针
}

int main() {
    int* p = nullptr;
    modifyPointer(&p);
    // p 现在指向新分配的 int
    delete p;  // 记得释放内存
}

方法2:使用指针的引用(更推荐)

void modifyPointer(int*& ptrRef) {
    ptrRef = new int(30);  // 直接修改原始指针
}

int main() {
    int* p = nullptr;
    modifyPointer(p);
    // p 现在指向新分配的 int
    delete p;
}

4. 原始代码问题分析

void func(..., int* max, int* min) {
    max = &a;  // 这只修改了局部副本
    min = &b;  // 这只修改了局部副本
}

这些赋值操作只修改了函数内部的指针副本,不会影响 main() 中的原始指针。

5. 解决方案对比

方法示例优点缺点
返回值int* func()简单只能返回一个值
二级指针func(int** max)可以修改多个指针语法复杂
指针引用func(int*& max)语法简洁需要C++引用支持
修改指向的内容func(int* max)最简单需要预先分配内存

6. 最佳实践建议

  1. 如果只需要修改指针指向的内容,使用一级指针
  2. 如果需要修改指针本身,优先使用指针引用 (int*&)
  3. 在C代码中或需要兼容C时,使用二级指针 (int**)
  4. 考虑使用智能指针 (std::unique_ptr&) 来避免内存管理问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值