C++ 传值 vs 传指针 vs 传引用
一句话:传值给函数一个副本(改动出不去)。指针和引用都给它真身(改动出得去)。指针可以为空、可以挪;引用是绑死不变的别名。小东西默认传值,大对象只读传 const 引用。
亲眼看区别 — 两个函数都想把参数改成 0,只有一个成功:
#include <iostream>
using namespace std;
void tryToZero(int x) { x = 0; } // 副本 — 调用方看不见
void actuallyZero(int* x) { *x = 0; } // 真身的地址
int main() {
int a = 5, b = 5;
tryToZero(a);
cout << "after tryToZero: " << a << endl;
actuallyZero(&b);
cout << "after actuallyZero: " << b << endl;
return 0;
}
本页演示用指针,因为我们浏览器引擎暂不支持引用参数(int&)— 但下面的规则对引用同样成立,语法会用代码块展示。
三种方式并排看
| 传值 | 传指针 | 传引用 | |
|---|---|---|---|
| 写法 | f(int x) | f(int* x),调用 f(&a) | f(int& x),调用 f(a) |
| 到函数手里的是 | 副本 | 对象的地址 | 对象的别名 |
| 调用方看得到改动? | 否 | 是 | 是 |
| 能"没有对象"吗? | 否 | 能 — 空指针 | 不能 — 必须绑定 |
| 拷贝开销 | 每次调用整份拷贝 | 一个地址 | 一个别名 |
经典场景:交换两个变量
swap 必须改调用方的变量,副本毫无用处 — 你需要地址:
#include <iostream>
using namespace std;
void mySwap(int* a, int* b) {
int t = *a; // 存下 a 指向的值
*a = *b;
*b = t;
}
int main() {
int x = 1, y = 2;
mySwap(&x, &y);
cout << x << " " << y << endl; // 2 1
return 0;
}
引用版在调用处更清爽 — 机制相同,没有 &/* 的噪音:
void mySwap(int& a, int& b) {
int t = a;
a = b;
b = t;
}
// 调用:mySwap(x, y); // 长得像传值,行为像指针
冷知识:数组永远按指针传
C 风格数组传进函数时,实际到达的是首元素指针 — 尺寸不会跟过去。所以收数组的函数都要再收一个长度:
#include <iostream>
using namespace std;
int sum(int arr[], int n) { // arr 实际是 int*
int s = 0;
for (int i = 0; i < n; i++) s += arr[i];
return s;
}
int main() {
int a[3] = {10, 20, 30};
cout << sum(a, 3) << endl;
return 0;
}
那我到底用哪个?
- 只读的小值(
int、double、char):传值。拷贝免费,函数也弄不坏你的变量。 - 只读的大对象(长字符串、大 vector):传
const引用 —const std::string& text。不拷贝,调用方对象也受保护。 - 函数必须改调用方的变量:引用(或指针)。引用更好读;指针是 C 时代的方式。
- "可能没有对象"是真实情况:指针,用前查空。引用不能为空 — 这是它的超能力也是它的限制。
- C 数组:不管你愿不愿意它都退化成指针 — 长度永远单独传。
值得备好的面试追问
- "指针 vs 引用 — 各给一个具体理由。" 指针:可为空、可重指向。引用:必须指东西、永远不用
*检查。 - "大对象为什么传 const 引用?" — 省拷贝是主要矛盾;
const保证只读。 - "
int& f()返回局部变量的引用错哪了?" — 局部变量函数一返回就死了,引用比对象活得长。未定义行为,经典陷阱题。 - "传值一定发生拷贝吗?" — C++11 起,移动语义可以把临时对象的昂贵拷贝变成便宜的移动。
去练习场练手
- 写
addOne(int* p),给调用方的变量加一;调用后打印确认。 - 把
mySwap改成"传指针的值" — 即只交换函数内部的两个指针 — 向自己解释为什么调用方毫无变化。 - 用传值写
maxOf(int a, int b, int c),体会小值传值为什么是正确的默认。
相关:15 道初学者面试题(指针 vs 引用是第 1 题)、++i 与 i++、整数除法。