文章目录
基本语法
c++
int a = 10;
int &b = a; // b 是 a 的引用(别名)
- 定义引用必须初始化,不能单独写 int &b;
- 变量名 a、b 随便起,和原变量名不需要一致
效果演示
c++
int a = 10;
int &b = a;
b = 999;
// a 也会变成 999
函数引用传参
普通传参(值传递)
c++
void test(int x){
x = 1024;
}
// 外部变量不会变!
原理:函数内是副本,修改的是复制出来的新变量,和外部无关。
引用传参(地址传递、修改原变量)
c++
void test(int &x){
x = 1024;
}
// 外部实参直接被修改
效果展示
c++
#include<stdio.h>
void test (int &x){
x = 1024;
printf("test函数内部的x值:%d \n",x); // 1
}
int main (){
int x = 1;
printf("调用函数前x的值:%d \n",x); // 1024
test(x);
printf("调用函数后x的值:%d \n",x); // 1
}
理解:main 中的 x 在内存有一块空间;调用 test 时,test 里的 x 只是这块空间的另一个名字,操作同一个内存格子。
核心机制
引用是"变量的别名。
如:int &x 中的 & 在这里是类型修饰符,而不是取地址运算符。
语义:声明x是某个已存在整型变量的别名 。此后,对x的任何操作,都直接等同于对原变量的操作。
底层本质
在汇编/机器码层面,引用在底层完全是指针的实现。它们都传递地址,都只占 8 字节(64位系统)。唯一的区别在于语法糖:
| 特征 | C 语言指针 int *p | C++ 引用 int &r |
|---|---|---|
| 底层实现 | 存储变量的地址 | 存储变量的地址(完全一样) |
| 初始化 | 可以不初始化(野指针风险) | 必须初始化,且绑定后不可更改 |
| 解引用 | 必须显式使用 *p 来取值/赋值 | 编译器自动解引用,直接写 r 即可 |
| 能否为 NULL | 可以(p = NULL) | 不可以 |
| 能否能重新指向 | 可以(p = &other) | 不可以(绑定后只能指向同一个变量) |
C++
void swap_ref(int &a, int &b) { // 形参是引用
int temp = a; // 直接使用 a,相当于 *a,但不用写 *
a = b; // 直接修改实参
b = temp;
}
// 调用:swap_ref(x, y); // 直接传变量,不需要 & 取地址
指针与引用的比较
功能:完全等价,都能修改外部原变量
C语言指针写法(繁琐)
c
void test(int *x){
*x = 1024;
}
// 调用必须传地址
test(&num);
C++ 引用写法(简洁)
c++
void test(int &x){
x = 1024;
}
// 调用直接传变量
test(num);
注意
- 形参名和实参名必须一样吗?
- 结论:完全不需要一致!!引用绑定的是内存地址,不是变量名字。
- 记忆:别名只是外号,外号和本名不需要相同。
- 指针:形参 *x,调用 &变量,内部 *x 解引用
- 引用:形参&x,调用直接写变量,内部直接用
易错点
错误1:引用不初始化
c++
int &a; // 非法
错误2:绑定常量
c++
int &a = 10; // 非法
错误3:更改引用指向(不能改嫁)
c++
a = b; // 这是赋值,不是更换引用指向