一、基本概念:先搞懂“是什么”¶
在C++中,引用(Reference)和指针(Pointer)都与“变量的地址”或“别名”相关,但本质截然不同:
-
引用:是变量的别名,它与原变量共享同一块内存空间,必须在定义时绑定到一个已存在的对象,且一旦绑定就无法再指向其他对象。
比如:int a = 10; int& ref = a;这里ref就是a的别名,修改ref就等于修改a。 -
指针:是一个存储地址的变量,它可以指向某个变量的内存地址,也可以为
nullptr(表示不指向任何对象)。
比如:int a = 10; int* ptr = &a;这里ptr存储的是a的地址,通过*ptr可以访问a的值。
二、核心区别:这5点必须分清¶
| 对比项 | 引用(Reference) | 指针(Pointer) |
|---|---|---|
| 语法形式 | 定义时用 &,无额外空间(如 int& ref = a;) |
定义时用 * 和 &,本身占用内存(如 int* ptr = &a;) |
| 是否为空 | 不能为 nullptr(必须绑定对象) |
可以为 nullptr(表示未指向任何对象) |
| 初始化 | 必须在定义时初始化(如 int& ref = a;) |
可先不初始化(但通常需赋值合法地址或 nullptr) |
| 可变性 | 绑定后不可再指向其他对象(一生只能绑定一个) | 可随时修改指向(如 ptr = &b;) |
| 解引用 | 直接使用(如 ref = 20;) |
需用 * 解引用(如 *ptr = 20;) |
三、关键细节:初学者常犯的错误¶
-
引用不能单独存在
引用必须绑定到对象,不能像指针一样“悬空”。比如:int& ref;是错误的,必须写成int& ref = a;。 -
指针可“空”,引用不可
指针可以是nullptr(表示无有效指向),例如int* ptr = nullptr;;而引用若为nullptr会直接报错。 -
大小不同
- 引用的大小与被引用类型相同(如int&大小是int的大小,4字节)。
- 指针的大小固定(32位系统4字节,64位系统8字节),与指向的类型无关。
四、使用场景:什么时候用引用?什么时候用指针?¶
优先用引用的场景:
1. 函数参数:避免大对象拷贝(如 void print(const string& s))。引用传递不会复制整个对象,效率更高。
2. 返回对象:避免返回大对象时的拷贝(如 string& getStr())。
3. 数组/容器别名:给数组或容器取别名(如 vector<int>& v = vec;)。
4. 重载运算符:如 string& operator[](int index)(类似C++标准库的数组访问)。
优先用指针的场景:
1. 动态内存管理:需手动分配/释放内存(如 int* p = new int[10];)。
2. 需修改指针指向:比如函数需改变指针的指向(如 void swap(int* a, int* b))。
3. 返回空指针表示失败:若函数可能无有效结果,用指针返回 nullptr(如 Node* findNode(int key))。
4. 数组或容器的动态访问:通过指针遍历数组(如 int* p = arr; p++;)。
五、代码示例:用起来更直观¶
例1:引用与指针的修改对比
int a = 10;
int& ref = a; // ref是a的别名
int* ptr = &a; // ptr指向a的地址
// 修改引用/指针,等价于修改原变量a
ref = 20; // 等价于 a = 20
*ptr = 30; // 等价于 a = 30
cout << a << endl; // 输出:30(ref和ptr都修改了a)
例2:引用与指针的不可变性
int x = 10, y = 20;
int& ref = x; // ref只能绑定x
ref = y; // 合法:ref=20(修改x的值为20)
// ref = &y; // 错误:引用不能重新指向其他对象!
int* ptr = &x;
ptr = &y; // 合法:ptr现在指向y
*ptr = 30; // 修改y的值为30
cout << y << endl; // 输出:30
六、总结:一句话记住¶
- 引用:变量的“别名”,简单、安全,适合直接访问对象(避免拷贝)。
- 指针:存储地址的“变量”,灵活但需手动管理(如空指针、内存释放),适合动态场景。
新手建议:优先用引用(安全、简洁),仅在必须处理空值或动态内存时用指针。
(注:本文代码基于C++11及以上标准,需注意编译器对引用的支持)