目录
引用不是新定义一个变量,而是给已存在的变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。 例如:在水浒传中,梁山的首领叫宋江,梁山好汉称呼他为公明哥哥,江湖人称他为及时雨,
类型& 引用变量名(对象名) = 引用实体;
- int main()
- {
- int a = 10;
- int& ra = a; //<====定义引用类型
- printf("%p\n", &a);
- printf("%p\n", &ra);
- }
验证:表明ra与变量a是同一个东西,正可谓一荣俱荣,一损俱损!
注意:引用类型必须和引用实体是同种类型的。否则会报错。

练习题:
- int main() {
- int a = 10;
- int& pa = a;
- int& x = a;
- int& y = x;
-
- x++;
- y++;
- pa++;
- a++;
- cout << "a的值为:" << a << endl;
- return 0;
- }
答案为:14,x作为变量a的引用,又被y当作引用引用,说到底还是变量a在++ 。

1. 引用在定义时必须初始化
2. 一个变量可以有多个引用
3. 引用一旦引用一个实体,再不能引用其他实体
对于第一点来说:

对于第二点来说,上个例题已经验证过了。
对于第三点:

- //指针用法
- void Swap1(int* pm, int* pn) {
- int tmp = *pm;
- *pm = *pn;
- *pn = tmp;
- }
-
-
- //引用用法
- void Swap2(int& m, int& n) {
- int tmp = m;
- m = n;
- n = tmp;
- }
-
- int main() {
- int aa = 10;
- int bb = 20;
- Swap1(&aa, &bb); //取地址
-
- int cc = 1;
- int dd = 2;
- Swap2(cc, dd); //不取地址
-
- cout << "aa:" << aa << " bb:" << bb << endl;
- cout << "cc:" << cc << " dd:" << dd << endl;
- }
结果:

我们会发现取地址的写法交换函数比引用写法的交换函数要复杂很多,这便是C++对于C语言使用指针的复杂性缺陷而研发出来的引用。
在之前学习数据结构链表的过程中,我通过使用二级指针去进行头插头删,因为修改结构体指针需要用到二级指针(改变指针地址的指针)
感兴趣的小伙伴可以去看看我写链表的博客:数据结构之链表详解(1)


![]()
指针的这种写法大大增加了代码的复杂性,可读性极差,而使用引用可以从根本上简化代码。给结构体指针的形参取别名,这样phead被修改了,那么plist也得变
- void SlistPushFront(struct Node*& phead, int x) {
-
- }
-
- int main() {
- struct Node* plist = NULL;
- SlistPushFront(plist, 1);
- SlistPushFront(plist, 2);
- return 0;
- }
这时会引发出一个问题:
1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
2. 引用在定义时必须初始化,指针没有要求
3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何 一个同类型实体
4. 没有NULL引用,但有NULL指针
5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32 位平台下占4个字节)
6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
7. 有多级指针,但是没有多级引用
8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
9. 引用比指针使用起来相对更安全
在效率上:
其实两者的效率是一致的,因为在底层中,指针和引用的参数都指向同一个地址。
在高级编程语言中,因为用*传参可能会指向空的地址或者错误的地址,所以要时时判断参数是否为空,导致降低效率。
而用&传参数,则参数不可能为空或者错误地址,这也算稍微提升了一些效率。
所以说各有各的好处,只是引用和指针在部分领域上互通可替换。