引用的概念
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
注意:共用内存空间,只是取一个别名.
当我们更改这个别名的值时,相当于将原来的变量的值更改
int b = 10;
int &a = b;
a = 0;
此时a的值为0;
从汇编层次上来看:
//案例代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//using namespace xue;
void fun(int& b)
{
b = 0;
}
int main(void)
{
int a = 10;
fun(a);
printf("%d", a);
}
从这个汇编指令可以看到 lea ,传的是地址,此时&b也管理这个地址, 而b就相当于被解引用。
引用与指针的区别
引用初始化的时候必须被赋值(指针初始化可以不被赋值),引用只能指向一次(只能可以指向不同的对象)。
int *a ;
int d = 0;
int& b = c ;//引用必须被初始化
a = &b; a = &d;
b = d; //实际上是d赋值给b,b并不是d的别名,b依旧是c的别名
提高效率:
引用传参可以提高效率
引用返回的意义
返回的是别名
int& fu()
{
int a = 0 ;
return a;
}//引用返回的别名所指的值是不确定的,当函数执行结束的时候,栈帧会被销毁,因此这个a不确定是否被销毁
int main(void)
{
int ret = fu();//在vs上没有被销毁
cout<<ret<<endl;
}
但是连续打印的时候会被销毁
int& fu()
{
int a = 0 ;
return a;
}
int main(void)
{
int ret = fu();//在vs上没有被销毁
cout<<ret<<endl;
cout<<ret<<endl;//此时ret的值已经被改变
}
总结:引用返回会出现各种麻烦的问题
但引用返回在对数组的元素改变十分方便。
typedef struct LS{
int arr[100];
int size;
}LS
void chage(SL* ps , int pos , int x )
{
assert(ps);
assert(pos<ps->size);
ps[pos] = x;
}
int& chage2(SL* ps, int pos)
{
assert(ps);
assert(pos<ps->size);
return ps->arr[pos];
}
int main(void)
{
SL s;
chage(&s,1,1);
change2(&s, 1) =1;
}
常引用:引用前提是不能扩大范围
int main(void)
{
const int a =10; int g = a;//把值拷贝给g
//int& b = a;//此时b不能给a取别名,因为a是常变量,此时权限被放大了。
const int& b = a;
int c = 0 ;
const int &d = c;//权限缩小了
int i =1;
//double& rj = i;//不可以范围扩大了
const double& rj = i ;//这个可以
}
类型转换:
i并不是直接变为double的,先赋给临时变量,而临时变量具有常性。
引用在底层上是开空间的
内联函数代替了宏
但是内联默认情况不会展开,编译器优化了。
如果是100行的内联函数,调用了一百次,
展开的情况100*100,不展开:100+100,
因此内联函数适合于频繁调用,但是代码行少的