引用的概念
引用可以看做是数据的一个别名,通过这个别名和原来的名字都能够找到这份数据。类似于windows的快捷方式。快捷方式可以有多个,通过执行快捷方式,就可以启动程序;同样的,一份数据也可以有多个引用,通过引用就可以修改原来的那份数据。
定义方式:
type &name = data;
type是引用的类型,类型必须与data的类型相同,name是引用的名称。
'引用必须在定义的同时初始化,不能再引用其它数据,类似于常量(const 变量)。'
演示代码:
#include <iostream>
using namespace std;
int main() {
int a = 100;
int &r = a;
cout << "a = " << a << endl;
cout << "r = " << r << endl;
cout << "a的地址:" << &a << endl;
cout << "r的地址:" << &r << endl;
r = 50;
cout << "a = " << a << endl;
cout << "r = " << r << endl;
cout << "a的地址:" << &a << endl;
cout << "r的地址:" << &r << endl;
return 0;
}
//输出
a = 100
r = 100
a的地址:007EFAD4
r的地址:007EFAD4
a = 50
r = 50
a的地址:007EFAD4
r的地址:007EFAD4
//可以看出,他们操作的是同一份数据,变量 r 只是变量 a 的另一个名字,他们俩的地址都一样。
//或者说地址为 007EFAD4 的内存有两个名字,a 和 r,想要访问该内存上的数据时,使用哪个名字都行。
//注意,引用在定义时需要添加&,在使用时不能添加&,使用时添加&表示取地址。
当变量的引用作为函数参数
当变量的引用作为函数参数在定义或声明函数时,可以将函数的形参指定为引用的形式,这样在调用函数时就会将实参和形参绑定在一起,让它们都指代同一份数据。如此一来,如果在函数体中修改了形参的数据,那么实参的数据也会被修改,从而拥有“在函数内部影响函数外部数据”的效果。
演示代码:
void swap1(int a, int b) {
int temp = a;
a = b;
b = temp;
}
void swap2(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
void swap3(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int num1 = 0;
int num2 = 0;
cout << "输入两个数:";
cin >> num1 >> num2;
swap1(num1, num2);
cout << "值传递:" << num1 << " " << num2 << endl;
cout << "输入两个数:";
cin >> num1 >> num2;
swap2(&num1, &num2);
cout << "指针传递:" << num1 << " " << num2 << endl;
cout << "输入两个数:";
cin >> num1 >> num2;
swap3(num1, num2);
cout << "引用传递:" << num1 << " " << num2 << endl;
return 0;
}
//输出:
输入两个数:10 50000
值传递:10 50000
输入两个数:10 50000
指针传递:50000 10
输入两个数:10 50000
引用传递:50000 10
//从以上代码的编写中可以发现,按引用传参在使用形式上比指针更加直观。
引用作为函数返回值
/*在将引用作为函数返回值时应该注意一个小问题,
就是不能返回局部数据(例如局部变量、局部对象、局部数组等)的引用,
因为当函数调用完成后局部数据就会被销毁。*/
int &func(int &num) {
num += 10;
return num;
}
int main() {
int num1 = 10;
int num2 = func(num1);
cout << num1 << " " << num2 << endl;
return 0;
}
面试重点
指针和引用都可以间接访问和改变变量,但区别如下:
- 指针是一个变量,它保存了一个变量的内存地址;引用是一个变量的一个别名,和变量共享一块内存。
- 指针可以被重新赋值,指向不同的变量;而引用在初始化后就不能更改,始终指向同一个变量。
- 指针可以为
nullptr
(即空指针),表示不指向任何一个变量;引用必须绑定到一个变量,不能为nullptr
。 - 使用指针需要对其进行解引用以获取或修改其指向的变量的值;引用可以直接使用,无需解引用。
演示代码:
int main() {
int a = 10;
int b = 20;
//指针
int *p = &a;
cout <<"指针的值:"<< *p << endl;
p = &b;
cout <<"指针的值:"<< *p << endl;
//引用
int &r = a;
cout << "引用的值:" << r << endl;
// r = &b; //报错:引用不能被重新绑定
int &r2 = b;
r = r2; //此时r仍然引用a,但b的值已经赋给了a
cout << "引用的值:" << r << endl;
cout << &r << " " << &a << endl; //地址一致
cout << &r2 << " " << &b << endl; //地址一致
return 0;
}
在汇编层面,指针和引用,这两者没区别。引用会被c++编译器当做const指针来进行操作。
结论
- 引用只是C++语法糖,可以看作编译器自动完成取地址、解引用的指针常量;
- 引用区别于指针的特性都是编译器约束完成的,一旦编译成汇编就和指针一样;
- 引用只是指针的语法包装,本质上还是指针,故仍然存在风险,例如:
-
int * ptr = new int; *ptr = 100; int &ref = *ptr; delete ptr; ref = 200; // 对已经释放的内存解引用,程序直接崩溃;
- 引用由编译器保证初始化,使用方便,例如不用检查空指针;
- 引用有
const int &
,表示所引用的对象本身是个常量; - 指针既有
const int *
(指针所指的变量不可修改),也有int * const
(指针的指向不能修改); - 有指针引用,但是没有引用指针;
- 指针和引用在自增(++)和自减的含义不同:指针是指针运算,引用是所引用对象执行++或--;
- 尽量使用引用代替指针,在代码上更加直观,更具有易读性;
今天的分享就到这里,本文为c++基础知识分享,本人水平有限,如有错误和补充,请指正!