📄 一句话概括
传值调用 = 把实参的"值"复制一份给形参,函数只在复印件上折腾。它是 C++ 默认的调用方式,也是本章唯一的方式。最经典的一课:写个 swap 想交换两个数——换不动,因为换的是复印件。
📝 本节和前面几节的关系
6.3 讲了"跳进函数、跳回来",这一节回答"跳进去时带了什么"——答案:只带值,不带地址。这正是 6.2.2"形参是实参的复印件"那条结论正式上岗的地方。等你学到第 7 章指针、第 8 章引用,"传地址"才会出现——那时你才真的拥有"改原件"的能力。
一、什么是传值调用
int add(int a, int b); // 形参
add(x, y); // 实参 → 只把"值"复制进去
一句话特点:函数拿到的只是副本,改副本不影响原件。
| 传值调用(本章) | 传地址调用(第 7、8 章) | |
|---|---|---|
| 传过去的是什么 | 值的副本 | 变量的地址 |
| 函数能改原件吗 | 不能 | 能 |
| 安全性 | 高(外面改不动,天然隔离) | 低(外部数据会被改) |
| 代价 | 复制一份(数据大时费时) | 传地址本身很小,但风险高 |
二、经典翻车现场:写不动的交换函数
void swap(int x, int y) { // 看起来没问题
int t = x;
x = y;
y = t; // 在函数内部看,x 和 y 确实换过来了
}
int a = 3, b = 5;
swap(a, b);
cout << a << " " << b << endl; // 输出仍是 3 5 !
为什么? swap(a, b) 只把 3 和 5 这两个值复制给了 x、y。x、y 换得再漂亮,跟 a、b 也是两码事。
一句话比喻:就像把文件复印一份给对方改——你手里的原件,一个字母都不会变。
三、实例 04:使用传值调用
#include <iostream>
using namespace std;
void swap(int x, int y) { // 传值:收到的只是复印件
cout << " 换之前:x = " << x << ", y = " << y << endl;
int t = x; x = y; y = t;
cout << " 换之后:x = " << x << ", y = " << y << endl;
}
int main() {
int a = 3, b = 5;
cout << "调用前:a = " << a << ", b = " << b << endl;
swap(a, b);
cout << "调用后:a = " << a << ", b = " << b << endl;
return 0;
}
看到什么算成功:
调用前:a = 3, b = 5
换之前:x = 3, y = 5
换之后:x = 5, y = 3
调用后:a = 3, b = 5
三行输出把"传值"钉死了:中间两行证明函数里真的换了,最后一行证明外面真的一点没变。
顺带看一个正面例子——传值其实也是保护:函数里那些坐标、计数一旦被误改,调用方的原始数据毫发无伤。安全,是传值调用送的礼物。
30 秒实验:把 swap(a, b) 改成 swap(3, 5)(直接传两个常量),照样编过运行。这说明"能不能改原件"跟函数体写法无关,只跟传进去的东西里有没有"地址"有关。试完改回来。
四、常见误区
- "函数里改了参数,外面就改了"——本章永远不成立。想改外部,必须传地址(第 7、8 章)。
- "那本章的函数据就没法改外部数据了?"——还有两条侧门:① 改全局变量(6.4 会讲);② 改传进来的容器内容(第 7 章讲数组时会见到——数组名会"退化成地址",那是下一章的惊喜)。
- "传值一定浪费,能不用就不用"——小数据(
int/double/char)传值又快又安全,本来就是首选。只有数据很大(大数组、长字符串)时,复制的代价才值得计较。 - "
swap这个名字取错了"——名字没问题,方式有问题。等第 8 章,同一个swap会以正确的形式再出场一次。
自测三问(点开对答案)
1. 传值调用传的是什么?——实参值的**副本**,不是变量本身。 2. 为什么 `swap(a, b)` 换不动 `a`、`b`?——函数只拿到复制出来的 `x`、`y`,互换的是它们,原件另有其物。 3. 想通过函数改外部变量,该怎么做?——传地址(指针或引用),第 7、8 章的内容。- ☐ 6.3.2 嵌套调用(下一节)
相关笔记
- 函数调用 —— 跳进去、跳回来
- 形参与实参 —— 复印件不是原件
- 空函数 —— 无返回值时的"副作用"通道
- 🔷 C++基础 · 索引 —— 全课路线图