C++引用
引用
定义:类型& 引用变量名称 = 表变量名称;
1 | int main() { |
输出为
1 | a = 10, r = 10 |
没有二级引用:
1
2
3 int a = 10;
int &b = a;
int &&C = b;//c++11中叫右值引用
引用的特点
定义引用必须初始化
int a = 10;int &x //error没有空引用
int &y = nullptr; //error没有二级引用
1 |
|
const引用
1 | int main() { |
同样的,当我们定义一个常变量const int a = 10;,是否可以使用int& b = a;来创建他的引用?
1 | error C2440: “初始化”: 无法从“const int”转换为“int &” |
很可惜,如果为常变量,那么他的引用需要也是常性引用
1 | const int a = 10; |
但是,当变量a为普通的时,我们可以使用普通的引用&ra引用他,也可以通过常性引用const int& cra引用他
1 | int a = 10; |
关于字面量:
const引用也可以引用字面量
1
2
3 const int& a = 10;
//int tmp = 10;
//const int& a = tmp;
右值引用
用于绑定右值(临时对象、字面量等),常用于实现移动语义和完美转发。类型名 &x为左值(能取地址的变量)引用,不能取地址的则称为右值
1 | int&& rightrefval = 12; //类型&& 引用变量名 = 右值表达式; |
数组的引用
1 | const int N = 10; |
形似与数组指针,当我们想用指针指向数组时,不应该单纯的是int* p = &a,应该改为int(*p)[10] = &a。同样的,引用一个数组也应该为int(&ra)[N] = a。注意:我们可以引用一个数组,但不能创建一个元素是引用的数组
指针的引用
1 | int a = 20; |
1 | a = 20, *p = 20, *rp = 20 |
指针和引用的区别
指针和引用是 C++ 中用于间接访问变量的两种机制,两者在语法和功能上有相似之处,但本质和使用场景差异显著。
核心定义与本质区别
指针(Pointer):指针是一个变量,其存储的内容是另一个变量的内存地址。通过指针可以间接访问该地址对应的变量。例:int a = 10; int* p = &a;(p 存储 a 的地址,*p 表示访问 a)。
引用(Reference):引用是一个变量的别名,它与被引用的变量共享同一块内存空间,本身不占用额外内存。例:int a = 10; int& ref = a;(ref 是 a 的别名,操作 ref 等价于操作 a)。
关键语法与特性对比
| 特性 | 指针(Pointer) | 引用(Reference) |
|---|---|---|
| 初始化要求 | 可以不初始化(未初始化的指针为 “野指针”,危险);可初始化为 nullptr(空指针)。 |
必须在定义时初始化,且必须引用一个已存在的变量(不能引用空值)。 |
| 可修改指向 | 可以改变指向的对象(指针的值可被重新赋值)。 | 一旦初始化,不能改变引用的对象(始终绑定最初的变量)。 |
| 内存占用 | 占用独立内存空间(通常为 4 字节或 8 字节,取决于系统位数)。 | 不占用额外内存空间(仅作为原变量的别名)。 |
| 空值支持 | 可以指向 nullptr(空指针),表示不指向任何有效对象。 |
不支持空值,必须引用一个有效的变量(不存在 “空引用”)。 |
| 解引用操作 | 需要通过 * 运算符解引用才能访问指向的变量。 |
无需解引用运算符,直接使用引用名即可访问原变量。 |
| 取地址操作 | 对指针取地址(&p)得到指针自身的地址。 |
对引用取地址(&ref)得到被引用变量的地址(与 &a 等价)。 |
| 算术运算 | 支持指针算术(如 p++、p--),用于数组遍历等场景。 |
不支持算术运算(引用不是变量,无法进行地址偏移)。 |
| 多级嵌套 | 支持多级指针(如 int**p,指针的指针)。 |
不支持多级引用(不存在 “引用的引用”,如 int&& ref 是右值引用,非多级引用)。 |
使用场景差异
函数参数传递
指针作为参数:传递的是指针的副本(地址的拷贝),可通过解引用(
*p)修改原变量;也可传递指针的引用(int*& p)修改指针本身的指向。适合需要传递 “可选参数”(可传入nullptr表示无值)的场景。例:1
2
3
4
5
6
7
8
9void modify(int* p) {
if (p != nullptr) *p = 20; // 需判断空指针,否则可能崩溃
}
int main() {
int a = 10;
modify(&a); // 传入a的地址
modify(nullptr); // 允许传入空值
return 0;
}引用作为参数:传递的是原变量的别名,修改引用直接影响原变量,语法更简洁;无需判断空值(引用一定有效)。适合需要 “必选参数” 且避免拷贝大对象(如自定义类)的场景。例:
1
2
3
4
5
6
7
8
9void modify(int& ref) {
ref = 20; // 直接修改,无需解引用
}
int main() {
int a = 10;
modify(a); // 直接传变量,无需取地址
// modify(nullptr); // 编译错误,引用不能绑定空值
return 0;
}
函数返回值
指针作为返回值:可返回动态分配的内存(如
new int)或全局 / 静态变量的地址,但禁止返回局部变量的地址(局部变量销毁后地址无效,导致 “悬空指针”)。例:1
2
3
4
5
6
7int* create() {
return new int(10); // 正确:返回动态分配的内存
}
int* bad() {
int a = 10;
return &a; // 错误:返回局部变量地址,悬空指针
}引用作为返回值:可返回全局 / 静态变量或类的成员变量的引用,用于链式操作(如
cout <<重载),但禁止返回局部变量的引用(局部变量销毁后引用无效,导致 “悬空引用”)。例:1
2
3
4
5
6
7
8int& getGlobal() {
static int g = 10; // 静态变量,生命周期与程序一致
return g; // 正确:返回静态变量的引用
}
int& badRef() {
int a = 10;
return a; // 错误:返回局部变量引用,悬空引用
}
const 修饰场景
const 指针:有两种形式:
const int* p:指针指向的内容不可修改(常量指针);int* const p:指针本身的指向不可修改(指针常量)。
1
2
3const int a = 10;
const int* p = &a; // 正确:常量指针指向常量
*p = 20; // 错误:不能修改指向的常量const 引用:
const int& ref表示引用指向的内容不可修改,常用于函数参数(避免拷贝且防止修改原变量)。1
2
3
4void print(const int& ref) {
// ref = 20; // 错误:const引用不可修改
cout << ref << endl;
}



