GESP 6级
引用
6级 · 指针/STL/复杂度
💡 为什么重要
引用(Reference)是C++对C语言指针的"安全升级"。在函数传参、运算符重载、STL容器操作中,引用无处不在。GESP 6级考试经常考引用传参与值传参的区别。掌握引用后,你写出来的代码会比用指针更简洁、更安全。
📖 前置知识
- 指针基础(上一节的内容:& 取地址、* 解引用)
- 函数的定义和调用
- 值传参的概念(函数参数是副本)
🔍 什么是"引用"?
引用就是一个变量的别名。它不像指针那样存地址,而是直接"绑定"到原变量上——引用和原变量是同一个人的两个名字。
打个比方:假设你叫"小明",你还有个外号叫"小明子"。"小明"和"小明子"是同一个人。引用就像这个外号。
核心规则:
- 引用必须在声明时初始化(必须一开始就绑定一个变量)
- 引用一旦绑定,不能改成绑定其他变量
- 引用不能为空(不像指针可以为 nullptr)
- 对引用的任何操作,都是直接操作原变量
📐 核心语法
int a = 10;
int &r = a; // r 是 a 的别名
r = 20; // a 也变成20(因为r就是a)
cout << r; // 输出20
cout << a; // 输出20
声明语法:类型 & 引用名 = 原变量;
int &r = a; // r 是 a 的别名
r = 20; // a 也变成20(因为r就是a)
cout << r; // 输出20
cout << a; // 输出20
声明语法:类型 & 引用名 = 原变量;
💻 代码详解
📝 示例1:引用的基本使用
#include <iostream>
using namespace std;
int main() {
int a = 10;
// 创建引用r,作为a的别名
int &r = a; // r 和 a 指向同一块内存
cout << a << endl; // 输出10
cout << r << endl; // 输出10(r就是a,值一样)
r = 50; // 通过r修改值
cout << a << endl; // 输出50(a也被改了!因为r就是a)
a = 100; // 通过a修改值
cout << r << endl; // 输出100(r也跟着变了)
// 注意:r 不占额外内存,它和 a 是同一个地方
// &r == &a 为 true(地址相同)
return 0;
}
📝 示例2:引用作为函数参数(最常见用途)
#include <iostream>
using namespace std;
// 用引用实现swap:参数是原变量的别名,直接修改
void swap(int &a, int &b) {
// a 是 x 的别名,b 是 y 的别名
int t = a; // 保存a(即x)的值
a = b; // 把b(即y)的值赋给a(即x)
b = t; // 把保存的值赋给b(即y)
}
int main() {
int x = 1, y = 2;
cout << "交换前: x=" << x << ", y=" << y << endl;
// 输出: 交换前: x=1, y=2
swap(x, y); // x和y的别名传入函数
cout << "交换后: x=" << x << ", y=" << y << endl;
// 输出: 交换后: x=2, y=1
return 0;
}
📝 示例3:引用 vs 指针的对比
#include <iostream>
using namespace std;
// 指针版本:需要传地址,函数内用 -> 或 * 访问
void printByPointer(int *p) {
cout << *p << endl; // 要用解引用
}
// 引用版本:直接传,函数内当普通变量用
void printByReference(int &r) {
cout << r << endl; // 直接用,简洁!
}
int main() {
int a = 42;
printByPointer(&a); // 要加 & 取地址
printByReference(a); // 直接传,更方便
// 引用 vs 指针的区别:
// 1. 引用不能为空,指针可以为 nullptr
// 2. 引用不能改指向,指针可以重新指向其他变量
// 3. 引用使用时不需要 * 解引用,更简洁
// 4. 函数参数优先用引用,更安全
return 0;
}
📝 示例4:const 引用(常引用)
#include <iostream>
using namespace std;
// const引用:只能读,不能改
void print(const int &r) {
cout << r << endl;
// r = 100; // 错误!const引用不能修改
}
int main() {
int a = 42;
const int &r = a; // 常引用
cout << r << endl; // 输出42,可以读
// r = 100; // 错误!不能通过常引用修改
a = 100; // 但可以直接修改a本身
cout << r << endl; // 输出100
print(a); // 传参时常用 const 引用
// 好处:不复制数据(高效),又保证不被修改(安全)
return 0;
}
⚠️ 易错点
- 引用声明时不写 &:
int &r = a;的 & 是声明引用的语法,不是取地址!只在声明时才有这个含义 - 引用不初始化:
int &r;是错误的!引用必须在声明时就绑定一个变量 - 引用绑定了就不能改:
int a=1, b=2; int &r=a; r=b;—— 这不会让r变成b的引用,而是把b的值赋给a,a变成2 - 值传参 vs 引用传参混淆:如果函数参数不加 &(如
void f(int a)),函数内修改 a 不会影响外面的变量 - 把引用和指针搞混:引用是别名,不是指针。引用不能做
p++、不能为 null、不能重新绑定
🎯 练习建议
- 入门:写一个 swap 函数,分别用值传参、指针传参、引用传参三种方式实现,对比效果
- 进阶:写一个函数用引用同时返回两个值(如求两个数的和与差)
- 思考:为什么标准库的 sort、push_back 等函数参数都用引用?
- 对比练习:写两个版本的函数,一个传值一个传引用,观察传递大型结构体时的性能差异