引用的概念与使用
困难5引用:给变量起个"小名"
想象一下,你在学校叫"张明",回家后妈妈喊你"小明",叫的都是同一个人。C++里的引用干的就是类似的事——给一个已经存在的变量起一个别名,两个名字指向同一块内存空间。也就是说,改别名就是改原变量,看别名就是看原变量。
引用最大的特点是:定义时必须绑定一个变量,并且一辈子不能换人。它不像指针那么自由(指针可以指向别处),但也因此更安全、更简单。
1. 引用的三个核心规则
| 规则 | 说明 | 生活类比 |
|---|---|---|
| 必须初始化 | 声明引用时必须指定它绑定的变量 | 你给朋友起外号,必须得有个朋友才能起 |
| 不能改变指向 | 引用一旦绑定,就永远是那个变量,不能再绑别的 | 小名"明明"永远指的是张明,不会变成李华 |
| 与原变量同地址 | 引用和原变量是同一块内存的两个名字 | 你的身份证号只有一个,大名和小名都指向同一个你 |
看这个例子更清楚:
#include <iostream>
using namespace std;
int main() {
int score = 90; // 原始变量:考试成绩90分
int& ref = score; // ref 是 score 的引用(别名)
cout << "score = " << score << endl; // 输出90
cout << "ref = " << ref << endl; // 输出90,因为它们是同一个值
ref = 100; // 通过引用修改值
cout << "修改后 score = " << score << endl; // 输出100
// 输出地址,看看是不是一样的
cout << "&score = " << &score << endl;
cout << "&ref = " << &ref << endl; // 地址完全相同!
return 0;
}
输出结果(地址可能不同,但两个地址一样):
score = 90
ref = 90
修改后 score = 100
&score = 0x61ff08
&ref = 0x61ff08
你可以把 ref 当成 score 的"小名",写 ref 就是在操作 score 本身。
2. 引用 vs 指针:谁更顺手?
很多新手会把引用和指针搞混。它们都能间接操作变量,但使用体验差别很大:
| 特性 | 引用 | 指针 |
|---|---|---|
| 必须初始化 | 是,不初始化就报错 | 可以不初始化,但野指针很危险 |
| 能否改变指向 | 不能,一生只绑一个 | 可以,随时指向别处 |
| 使用方式 | 像普通变量一样直接用 | 需要 * 解引用才能拿到值 |
| 安全性 | 更安全(永远不会是空引用) | 容易野指针、空指针 |
| 有无自己的地址 | 没有,它就是原变量的别名 | 有自己的地址(指针变量存的地址) |
生活例子:引用就像你手机里的"快捷拨号",按一下就打给妈妈,不能改成爸爸。指针就像一个"通讯录条目",里面存着别人的号码,你可以擦掉改写成另一个号码,但操作时需要先找到这个条目(取地址 &),再拨号(解引用 *)。
3. 引用在函数中的妙用——不用复制,直接改
引用最常用的地方是函数参数。如果不加引用,参数会被复制一份,函数里改的是副本,不影响原变量。加上引用,函数就能直接修改传入的变量,而且不需要指针那么麻烦。
例子:交换两个数的值
#include <iostream>
using namespace std;
// 使用引用作为参数,函数可以直接修改传入的变量
void swap(int& a, int& b) { // a 是 x 的引用,b 是 y 的引用
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 5, y = 10;
cout << "交换前:x = " << x << ", y = " << y << endl; // 5, 10
swap(x, y); // 传的是引用,函数内部改的就是 x 和 y 本身
cout << "交换后:x = " << x << ", y = " << y << endl; // 10, 5
return 0;
}
如果不加引用(改成 void swap(int a, int b)),swap(x, y) 只会交换两个副本,x 和 y 的值不变。引用就像给了函数一把"万能钥匙",可以直接打开原变量的门。
例子:通过引用修改数组元素
#include <iostream>
using namespace std;
int main() {
int scores[3] = {85, 90, 78}; // 三科成绩
// 遍历数组,用引用给每个成绩加5分(平时分加满!)
for (int i = 0; i < 3; i++) {
int& ref = scores[i]; // ref 是 scores[i] 的别名
ref += 5; // 直接修改原数组元素
}
for (int i = 0; i < 3; i++) {
cout << scores[i] << " "; // 输出 90 95 83
}
return 0;
}
4. 引用作为返回值——小心返回局部变量的引用!
函数也可以返回引用,这样调用者就能直接操作函数内部返回的那个变量。但有一个大坑:千万不要返回局部变量的引用,因为局部变量在函数结束时就被销毁了,引用会指向一块已经被回收的内存,导致崩溃或乱码。
正确用法:返回全局变量、静态变量或参数中传来的引用。
#include <iostream>
using namespace std;
int global = 100; // 全局变量
// 返回全局变量的引用(安全)
int& getGlobal() {
return global; // 返回引用,调用者可以修改 global
}
int main() {
cout << "原值:" << global << endl; // 100
getGlobal() = 200; // 函数返回的是引用,可以直接赋值修改
cout << "修改后:" << global << endl; // 200
return 0;
}
错误示例(千万不要这样写!):
int& badFunction() {
int local = 5; // 局部变量
return local; // 危险!函数结束 local 就没了
}
5. 新手常犯的 3 个错误
错误①:忘记初始化引用
int& ref; // 编译错误!引用必须初始化,否则不知道是谁的小名
正确做法:声明时绑定一个变量。
错误②:试图改变引用的指向
int a = 10, b = 20;
int& ref = a; // ref 绑定 a
ref = b; // 这不是让 ref 绑定 b,而是把 b 的值赋给 a(a 变成20)
很多新手以为 ref = b; 会让 ref 转而绑定 b,但实际上它只是把 b 的值赋给 a。引用一辈子只跟第一个变量走。
错误③:返回局部变量的引用(前面已经强调过)
6. 完整可运行示例:用引用实现多重功能
下面这段代码展示了引用在参数、数组操作和返回值中的典型用法:
#include <iostream>
using namespace std;
// 用引用交换两个数
void my_swap(int& x, int& y) {
int t = x;
x = y;
y = t;
}
// 用引用给数组中每个元素加一个值
void add_to_all(int arr[], int size, int add_value) {
for (int i = 0; i < size; i++) {
int& ref = arr[i]; // 引用数组元素
ref += add_value;
}
}
int main() {
// 1. 引用基本用法:交换
int a = 10, b = 20;
cout << "交换前:a=" << a << " b=" << b << endl; // 10 20
my_swap(a, b);
cout << "交换后:a=" << a << " b=" << b << endl; // 20 10
// 2. 引用修改数组
int scores[5] = {80, 85, 90, 75, 88};
add_to_all(scores, 5, 5); // 每个成绩加5分
cout << "加5分后的成绩:";
for (int i = 0; i < 5; i++) {
cout << scores[i] << " "; // 85 90 95 80 93
}
cout << endl;
// 3. 引用绑定的不可变性验证
int c = 100;
int& ref_c = c; // ref_c 绑定 c
int d = 200;
ref_c = d; // 这不是换绑定,而是把 d 的值赋给 c(c变成200)
cout << "c = " << c << ", ref_c = " << ref_c << ", d = " << d << endl; // 200 200 200
// 注意:ref_c 仍然绑定的是 c,不是 d
return 0;
}
7. 相关知识点指引
- 指针:引用和指针是"表兄弟",学完引用可以对比学习指针,理解它们各自的适用场景。
- 函数参数传递方式:值传递、引用传递、指针传递,这是C++函数设计的核心。
- 常量引用(
const int&):既能避免复制,又防止函数内修改原变量,非常常用。 - 动态内存与指针:处理动态分配的数组或对象时,指针更灵活,引用通常用于函数接口。
掌握了引用,你的C++代码会更简洁、更高效。下次写交换函数时,别忘了用引用代替指针,少敲几个星号,多一份安全!
例题精讲
关于C++中的引用,以下说法正确的是?
下列代码中,哪个函数能正确交换两个整数的值?
在C++中,引用定义时如果不初始化,后续可以通过赋值操作使其绑定到某个变量。
以下函数使用引用返回数组某个元素的值,请补全代码。
int arr[5] = {1,2,3,4,5};
int& getElement(int index) {
return ___;
}
int main() {
getElement(2) = 100; // 将arr[2]修改为100
cout << arr[2]; // 输出100
return 0;
}以下函数希望通过引用参数修改外部变量的值,请补全代码。
void increment(___ x) {
x++;
}
int main() {
int num = 5;
increment(num);
cout << num; // 应输出6
return 0;
}