C++: 引用
最后更新:2026-08-26
指针虽然强大,但用起来有点麻烦——要写
*p解引用,还要注意空指针。C++ 引入了引用(Reference)——变量的"别名",用起来比指针更安全、更简洁。
1. 什么是引用?
(1) 1.1 生活中的引用
| 生活场景 | 程序中的对应 |
|---|---|
| 你有个外号"小明",叫哪个都能找到你 | 引用(变量的别名) |
| 身份证上的名字和日常用的名字 | 引用和原变量 |
引用的本质: 引用是变量的别名——对引用的操作,就是对被引用变量的操作。
(2) 1.2 为什么需要引用?
用指针(麻烦):
▶ 示例 2:代码示例(难度⭐)
#include <iostream>
void modifyValue(int* x) {
*x = 100; // 要解引用
}
int main() {
int a = 5;
modifyValue(&a); // 要传地址
std::cout << a << std::endl; // 100
return 0;
}
输出:
(程序输出)
用引用(简单):
#include <iostream>
void modifyValue(int& x) { // x 是引用
x = 100; // 直接用,不用解引用
}
int main() {
int a = 5;
modifyValue(a); // 看起来像传值,其实是传引用
std::cout << a << std::endl; // 100
return 0;
}
2. 引用的声明与初始化
(1) 2.1 声明引用
语法:
类型& 引用名 = 原变量;
示例:
#include <iostream>
int main() {
int x = 5;
int& ref = x; // ref 是 x 的别名
std::cout << "x = " << x << std::endl; // 5
std::cout << "ref = " << ref << std::endl; // 5
ref = 100; // 修改 ref 就是修改 x
std::cout << "修改后 x = " << x << std::endl; // 100
return 0;
}
💡 重点: 引用必须初始化——不能先声明,后赋值。
(2) 2.2 引用 vs 指针
| 对比 | 引用 | 指针 |
|---|---|---|
| 语法 | int& ref = x; |
int* p = &x; |
| 是否能为空 | ❌ 不能(必须初始化) | ✅ 能(nullptr) |
| 是否要解引用 | ❌ 不用(直接用) | ✅ 要(*p) |
| 能否重新指向 | ❌ 不能(一旦绑定,不能改) | ✅ 能(可以指向别的变量) |
| 推荐程度 | ⭐⭐⭐⭐⭐(优先用) | ⭐⭐⭐(必要时用) |
3. 引用作为函数参数*
(1) 3.1 基本用法
#include <iostream>
// 用引用参数"返回"多个值
void minMax(int arr, int length, int& min, int& max) {
min = arr[0];
max = arr[0];
for (int i = 1; i < length; i++) {
if (arr[i] < min) {
min = arr[i];
}
if (arr[i] > max) {
max = arr[i];
}
}
}
int main() {
int arr[5] = {3, 1, 4, 1, 5};
int min, max;
minMax(arr, 5, min, max); // min 和 max 会被修改
std::cout << "最小值:" << min << std::endl; // 1
std::cout << "最大值:" << max << std::endl; // 5
return 0;
}
💡 重点: 引用参数让函数能"返回"多个值(因为可以修改多个引用参数)。
(2) 3.2 const 引用(最常用)
如果你不想让函数修改参数,但又想避免复制开销,可以用 const 引用。
#include <iostream>
#include <string>
void printName(const std::string& name) { // const 引用:不能修改 name
std::cout << "名字:" << name << std::endl;
// name = "Alice"; // ❌ 错误:不能修改 const 引用
}
int main() {
std::string myName = "MOTO";
printName(myName); // 不用复制整个字符串,效率高
return 0;
}
💡 黄金法则: 函数参数优先用 const 引用——兼顾安全性和效率。
4. 引用的陷阱*
(1) 4.1 引用必须初始化*
#include <iostream>
int main() {
int& ref; // ❌ 错误:引用必须初始化
return 0;
}
编译错误信息:
error: 'ref' declared as reference but not initialized
(2) 4.2 引用不能重新绑定*
#include <iostream>
int main() {
int x = 5;
int y = 10;
int& ref = x;
ref = y; // ❌ 这不是重新绑定!这是把 x 的值改成 y 的值
std::cout << "x = " << x << std::endl; // 10
std::cout << "y = " << y << std::endl; // 10
return 0;
}
💡 重点: 引用一旦绑定到某个变量,不能重新绑定到另一个变量。
5. 实战:多个返回值*
▶ 示例 1:计算商和余数(难度⭐⭐)
#include <iostream>
// 用引用参数"返回"多个值
void divide(int a, int b, int& quotient, int& remainder) {
quotient = a / b;
remainder = a % b;
}
int main() {
int a = 17, b = 5;
int q, r;
divide(a, b, q, r); // q 和 r 会被修改
std::cout << a << " / " << b << " = " << q << " ... " << r << std::endl;
// 输出:17 / 5 = 3 ... 2
return 0;
}
输出:
/ = ...
▶ 示例 3:引用作为函数返回值(难度⭐)
#include <iostream>
#include <string>
std::string name = "张三"; // 全局变量
// 返回引用(不是值)
std::string& getName() {
return name; // 返回的是 name 的引用
}
int main() {
getName() = "李四"; // 修改全局变量
std::cout << "name = " << name << std::endl;
return 0;
}
输出:
name =
❓ 常见问题
Q:引用和指针到底有什么区别? A:> - 引用是变量的别名,指针是存储地址的变量 > - 引用必须初始化,指针可以是
nullptr> - 引用不能重新指向,指针可以 > - 优先用引用,除非需要表示"没有"(这时用指针) Q:为什么数组作为参数时,不能用引用? A:可以用,但要写 数组引用 的语法(比较复杂)。更简单的方法: 用
std::array或std::vector(后面会学)。
Q:引用能提高程序运行效率吗? A:不能。引用在底层通常就是用指针实现的,运行效率和指针一样。
它提高的是开发效率(代码更简洁、不易出错)。
Q:关于references最重要的是什么? A:先理解核心概念,再通过实践例子来巩固。
📖 小节
- 引用是变量的别名,声明必须初始化
- 引用 vs 指针:引用不能为空、不能重新绑定
- 引用作为函数参数:修改外部变量、避免拷贝
- const 引用可绑定临时对象(延长生命周期)
- 引用返回值可作为左值
📝 作业
-
基础题 (Difficulty ⭐): 写一个函数
void addTen(int& x),给传入的变量加 10。在main里测试。 -
进阶题 (Difficulty ⭐⭐): 写一个函数
void swap(int& a, int& b),交换两个变量的值。在main里测试。 -
挑战题 (Difficulty ⭐⭐⭐): 写一个程序,实现"三个数排序":
-
写一个函数
void sortThree(int& a, int& b, int& c),把三个数按从小到大排序 -
在
main里让用户输入三个数,调用sortThree,然后输出排序后的结果
6. 🚀 下一步*
学会了引用,接下来我们学习 动态内存分配(第26课)—— 用 new 和 delete 手动管理内存,理解堆和栈的区别。