前言
在《水浒传》中,梁山一百零八好汉,每个人都有一个响亮的外号,比如,当我们提到李逵和提到黑旋风提到铁牛时,本质上我们指的是同一个人。黑旋风江州劫法场,那李逵,铁牛也有江州劫法场的经历。引用也是这个道理。
引用
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
可以看出,a和b的关系就如同鲁迅和周树人的关系一样,a和b指向同一个内存空间。
合法的引用语法要求为:
- 引用必须初始化
- 引用定义后不能改变指向 (由于这条特性,引用不能完全代替指针)
- 一个变量可以有多个引用
int a = 10;
int& b = a; //正确
int& c = 10;//错误,不能对常量引用
int& d; //错误,没有初始化
引用做参数传参
把引用作为函数的参数传递,由于他们两个指向的是同一块内存空间,可以通过修改引用的值来间接修改函数外变量的值。
举个例子,在c风格的swap函数中,需要通过传地址来间接修改值,在cpp中使用引用就可以不调用指针实现。
//c
void swap_c(int* x, int* y)
{
int tmp = *x; *x = *y; *y = tmp;
}
//c++
void swap_cpp(int& x, int& y)
{
int tmp = x; x = y; y = x;
}
用引用来代替指针是一个不错的做法,可以显著提高代码可读性,但是由于引用不能修改指向,所以引用不能完全代替指针(如前序遍历链式二叉树,需要递归更改指针的值,也就是地址,引用显然不适合)
引用做函数返回值
请注意,当引用做返回值时,地址必须在静态区,如全局变量,动态内存,否则会出现野引用的错误。
野引用:
显然,这是一段很狗屎的代码,引用ret1和ret2的地址为函数tmp中的一个地址,函数结束后,该内存中的值销毁,故ret1和ret2在tmp外查看时为一个随机值,且它们俩地址是一样的,幸亏引用的特性让他们不行被修改,不然他们和野指针的效果是一样的。
引用的底层实现原理
让我们写出这样一段代码。
int main()
{
int x = 10;
int& y = x;
int m = 10;
int* n = &m;
system("pause");
return 0;
}
然后转到反汇编
有十分甚至九分的相似
引用和指针,在底层其实是一样的
同理,引用也会消耗内存来存储地址,只是这块内存找不到罢了。
一些吐槽
不知道大家在阅读一些比较老的c语言数据结构书籍时有没有遇到这样的一段代码(应该在双向链表部分),它会给这么一段cpp的代码(请注意看它新建文件时给的后缀)
//这是一个双向链表
typedef struct Node {
struct Node* next;
struct Node* prev;
int val;
}LNode,*PNode;
void PushBack(PNode& pnode, int val)
{
;//布拉布拉
}
按照原本c语言的逻辑:因为在PushBack函数中需要递归更改原链表的指针的值,需要向函数中传一个二级指针,也就是*PNode。但是,或许是书的作者觉得指针不好理解,就给了一个c++的引用,这属实时有点离谱。
感谢观看!!!