3.3 参数传递方式
1 值传递
值传递的原理
值传递就像复印文件:你把原件拿去复印,函数拿到的是复印件,对复印件的任何修改都不会影响原件。
内存原理:
- 调用函数时,参数的值会被复制一份
- 函数内操作的是这个副本
- 函数返回后,副本被丢弃,原变量不受影响
示例程序演示
#include <iostream>
using namespace std;// 值传递函数
void incrementByValue(int num) {num++;cout << "函数内num的值: " << num << endl;
}int main() {int a = 5;incrementByValue(a);cout << "main函数中a的值: " << a << endl; // 仍然是5return 0;
}
输出结果:
函数内num的值: 6
main函数中a的值: 5
值传递的局限性
- 无法修改原变量:函数内的修改不会影响调用处的变量
- 效率问题:对于大型结构体或类对象,复制开销大
- 内存消耗:每次调用都会创建新的副本
适用场景:
- 基本数据类型(int, double等)
- 不需要修改原变量的情况
- 需要保护原数据不被意外修改
2 引用传递
引用符号(&)的使用
引用就像给变量起别名,使用&
符号声明:
void incrementByRef(int &num) { // 注意&符号num++;
}
修改原变量的示例
#include <iostream>
using namespace std;void swapByRef(int &x, int &y) {int temp = x;x = y;y = temp;
}int main() {int a = 3, b = 5;cout << "交换前: a=" << a << ", b=" << b << endl;swapByRef(a, b);cout << "交换后: a=" << a << ", b=" << b << endl;return 0;
}
输出结果:
交换前: a=3, b=5
交换后: a=5, b=3
趣味练习:交换变量值
#include <iostream>
using namespace std;// 你的任务:实现这个交换函数
void mySwap(int &first, int &second) {// 在这里写下你的代码int temp = first;first = second;second = temp;
}int main() {int x = 10, y = 20;cout << "交换前: x=" << x << ", y=" << y << endl;mySwap(x, y);cout << "交换后: x=" << x << ", y=" << y << endl;// 测试用例if(x == 20 && y == 10) {cout << "恭喜!交换成功!" << endl;} else {cout << "再检查一下你的代码哦~" << endl;}return 0;
}
扩展挑战:
- 尝试用引用实现三个变量的轮换(a→b→c→a)
- 编写一个函数同时返回多个计算结果(如圆的面积和周长)
3 两种方式的比较
内存角度分析
值传递 | 引用传递 | |
---|---|---|
内存使用 | 创建参数副本 | 直接使用原变量 |
修改影响 | 不影响原变量 | 直接影响原变量 |
调用开销 | 需要复制数据 | 仅传递地址,效率高 |
安全性 | 高(保护原数据) | 低(可能意外修改原数据) |
使用场景建议
使用值传递当:
- 参数是基本数据类型(int, double等)
- 不需要修改原变量
- 希望保护原始数据不被修改
使用引用传递当:
- 需要修改原变量
- 参数是大型结构体或对象(避免复制开销)
- 需要实现多返回值(通过引用参数返回结果)
常见错误提醒
- 忘记加&符号:
void func(int x) {...} // 本想用引用但忘记&
- 传递字面量给非常量引用:
void print(int &x) {...}
print(5); // 错误!不能绑定临时值到非const引用
- 返回局部变量的引用:
int& badFunc() {int x = 10;return x; // 错误!x将很快被销毁
}
- 混淆指针和引用:
void func1(int &x) {...} // 引用
void func2(int *x) {...} // 指针
本章实验项目
成绩修改器
#include <iostream>
using namespace std;// 值传递版本(不会修改原成绩)
void adjustGradeByValue(int grade, int bonus) {grade += bonus;if(grade > 100) grade = 100;cout << "调整后成绩(函数内): " << grade << endl;
}// 引用传递版本(会修改原成绩)
void adjustGradeByRef(int &grade, int bonus) {grade += bonus;if(grade > 100) grade = 100;cout << "调整后成绩(函数内): " << grade << endl;
}int main() {int myGrade = 75;int bonusPoints = 10;cout << "原始成绩: " << myGrade << endl;// 测试值传递adjustGradeByValue(myGrade, bonusPoints);cout << "值传递后实际成绩: " << myGrade << endl;// 测试引用传递adjustGradeByRef(myGrade, bonusPoints);cout << "引用传递后实际成绩: " << myGrade << endl;return 0;
}
思考问题:
- 为什么值传递版本没有改变main函数中的myGrade?
- 如果bonusPoints也用引用传递会有什么影响?
- 什么情况下应该使用const引用?
本章总结表
特性 | 值传递 | 引用传递 |
---|---|---|
语法 | void func(int x) | void func(int &x) |
修改原变量 | 不能 | 能 |
内存开销 | 需要复制 | 仅传递引用(地址) |
典型用途 | 保护原始数据、基本类型 | 修改参数、大型对象传递 |
安全性 | 高 | 需谨慎使用 |
课后综合练习
- 基础题:编写一个函数
createFullName
,通过引用参数返回"姓氏+名字"的组合 - 提高题:实现一个计算器,使用引用参数同时返回加减乘除四个结果
- 挑战题:设计一个学生成绩处理器,使用引用修改学生成绩并返回是否及格
- 思考题:分析以下代码的问题并修复:
void increase(int x) {x++;
}int main() {int a = 5;increase(a);cout << a; // 期望输出6,实际输出5return 0;
}
编程小项目:创建一个简单的银行账户系统,包含以下功能:
deposit
:存款(修改余额)withdraw
:取款(修改余额)transfer
:转账(修改两个账户余额)
所有金额修改都应使用引用传递实现