1. 参数传递的本质:从内存角度看形参与实参
在C++函数调用过程中,形参(formal parameter)和实参(actual argument)的关系就像快递柜的寄存与取件。当我们在main函数中写下func(a)时,变量a就是实参——它是我们要传递的真实数据。而函数定义中的void func(int b)里的b就是形参——它是接收数据的"快递柜格子"。
这个过程中会发生一个关键操作:实参的值被复制到形参的内存空间。对于基本数据类型(int、double等),这意味着在栈上会创建新的变量。例如:
cpp复制void increment(int x) {
x++;
}
int main() {
int a = 5;
increment(a);
cout << a; // 输出仍然是5
}
这里a的值5被复制给x,函数内对x的修改不会影响a,因为它们是两个独立的存储空间。这就是为什么新手常困惑"为什么函数里的修改没生效"——他们没意识到这是两个不同的变量。
关键理解:形参是函数的局部变量,它的生命周期仅在函数执行期间存在。每次函数调用结束时,这些形参占用的内存就会被释放。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 三种参数传递方式的深度解析
2.1 值传递(Pass by Value)
值传递是C++的默认方式,也是最容易理解但最容易踩坑的方式。它的核心特点是:
- 实参的值被完整复制到形参
- 函数内对形参的修改不影响原始数据
- 适用于小型数据(基本数据类型、小型结构体)
典型应用场景:
cpp复制double calculateArea(double radius) {
return 3.14159 * radius * radius;
}
这里使用值传递非常合适,因为:
- double类型占用固定8字节,复制成本低
- 函数不需要修改原始半径值
- 避免了意外的副作用
但值传递有个致命缺陷——当传递大型对象时:
cpp复制void processData(vector<int> data) { ... } // 糟糕!整个vector会被复制
这时应该改用引用传递。
2.2 引用传递(Pass by Reference)
引用传递通过&符号实现,它实际上传递的是变量的内存地址。关键特性:
- 形参是实参的别名(alias),共享同一内存空间
- 函数内对形参的修改直接影响原始数据
- 没有复制开销,适合大型对象
正确用法示例:
cpp复制void capitalize(string& str) {
for(auto& c : str) c = toupper(c);
}
这里必须用引用,因为:
- 字符串可能很长,复制代价高
- 函数需要修改原始字符串
- 希望调用者看到变化
但引用传递有个危险陷阱——可能意外修改数据。这时可以用const引用:
cpp复制void printLargeObject(const BigClass& obj) { ... }
这样既避免了复制,又防止了意外修改。
