🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ## 一、引用的特性: * 引用在定义时必须初始化 * 一个变量可以有多个引用 * 引用一旦绑定某个实体,就不能再是其他变量的引用。 ## 二、引用和指针的区别与联系: * 1.相同点: * 底层的实现方式相同,都是按照指针的方式实现的 * 2.不同点: * 引用定义的时候必须初始化,指针可以不用初始化; * 引用一旦初始化为指向一个对象,就不能再指向其他对象,而指针可以在任何时候指向任何一个同类型的对象; * 没有空引用,但是有空指针; * 在sizeof中的含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节的个数(在32为平台下,指针求sizeof永远是4); * 引用++改变的是变量的内容,指针++改变的是指针的指向; * 有多级指针,没有多级引用; * 引用使用起来比指针安全; * 如果返回动态内存分配的对象或者内存,必须使用指针,引用可能引起内存泄漏; ## 三、传值、传地址、传引用的区别,哪个更高效? * 1.传值 * 这种传递方式中,实参和形参是两个不同的地址空间,参数传递的实质是将原函数中变量的值,复制到被调用函数形参所在的存储空间中,这个形参的地址空间在函数执行完毕后,会被回收掉。整个被调用函数对形参的操作,只影响形参对应的地址空间,不影响原函数中变量的值,因为这两个不是同一个存储空间。 **即使形参的值在函数中发生了变化,实参的值也完全不会受到影响,仍为调用前的值。** * 2.传地址 * 这种传递方式中,实参是变量的地址,形参是指针类型的变量,在函数中对指针变量的操作,就是对实参(变量地址)所对应的变量的操作,函数调用结束后,原函数中的变量的值将会发生改变。 **被调用函数中对形参指针所指向的地址中内容的任何改变都会影响到实参。** * 3.传引用 * 这种传递方式中,形参是引用类型变量,其实就是实参的一个别名,在被调用函数中,对引用变量的所有操作等价于对实参的操作。这样,整个函数执行完毕后,原先的实参的值将会发生改变。 **被调函数对形参做的任何操作都影响了主调函数中的实参变量。** * 4.哪种更高效? * 在内置类型当中三种传递方式的效率上都差不多; * 在自定义类型当中,传引用方式效率的更高效一些,因为它没有对形参进行一次拷贝 ## 引用的使用场景 1.给变量起别名 2.将引用作为函数的参数 使用引用类型就不必在swap中声明形参是指针变量,指针变量要另外开辟内存单元,其内容是地址。而引用变量不是一个独立的变量,不单独占内存单元。而且在调用swap函数时,只需要传值即可,将引用作为函数的形参更加简单、直观、方便。 3.返回值 **C++不可以返回局部变量的引用或指针** ## 可以返回局部变量特例 ``` char *fun() { char *s = "1sfsdg"; return s;//返回的是1sfsdg的地址,1sfsdg存储在字符常量区,也就在静态存储区。而指针变量s的地址&s是在栈上,会随着函数的调用完被销毁。 } ``` 函数返回处产生一个对返回对象的“左值”s的拷贝,也就是在“左值”拷贝中存储了指向字符串常量1sfsdg的地址 **返回可以,因为返回的不是该函数的栈地址,而是静态存储区的地址。** ``` int  *fun() { int *a = new int[10]//动态数组数组的空间在堆上,而指针变量a的地址&a在栈上,占4个字节,存储着堆    上动态数组的首地址。 return a;//变量a的左值是一个局部变量指针,存储于函数栈上,右值 是“堆”的地址(“堆”的值是数组里面存的 值),函数返回处产生一个对返回变量的“左值”a的拷贝,也就是在“左值”的拷贝中存储了指向“堆”的地 址。 } ``` 返回可以。 ``` int *fun() { int a[10]  = {.......};//静态数组 return a;//静态数组,在预处理阶段就在该函数的栈上分配了空间,尝试返回一个栈地址,错误 } ``` 返回不可以。