什么是引用
所谓变量,其实是内存地址的一个抽像名字罢了,引用类型就是为一个变量创建一个别名。使得一个块地址空间可以有多个名字。好比关羽,关云长,关二爷,都是说的一个人。
例有以下代码:
#include<iostream>
using namespace std;
int main() {
int a = 10;
int& b = a;//b为a的别名。
cout << "a is " << a << endl << "b is " << b << endl;//访问b也就是访问a
cout << "&a is " << &a << endl << "&b is " << &b << endl;//a与b是同一块空间的不同名字
return 0;
}
a于b的关系:
输出结果:
如果再给b取别名,其实还是在给a起别名,因为b是a的别名,他们代表同一块内存空间。就像给关云长起别名,其实还是在给关羽起别名一样。
特殊规则
1.引用类型必须初始化并且只能初始化一次
错误实例1(引用类型必须初始化):
错误示例2(只能初始化一次):
这个代码会将c赋值给a,因为b一旦初始化为a的别名后就不可更改。
引用类型做函数形参
引用类型可以做函数的形参,在大部分情况下代替指针传参。
#include<iostream>
using namespace std;
void my_swap(int& a, int& b) {
int c = a;
a = b;
b = c;
}
int main() {
int x = 10;
int y = 20;
cout << "x is " << x << " " << "y is " << y << endl;
my_swap(x, y);
cout << "x is " << x << " " << "y is " << y << endl;
return 0;
}
引用类型做函数返回值
应用类型可以做函数的返回类型。
#include<iostream>
using namespace std;
int& test() {
static int t = 0;
return t;
}
int main() {
test() += 10;
test() += 10;
cout << test() << endl;
return 0;
}
要注意函数的栈帧都是临时创建的,要检查引用代表的空间是否已经还给操作系统,若栈帧已经销毁则引用代表空间里的值可能已经被覆盖。
风险实例:
动态开辟一个n个元素的数组
#include<iostream>
#include<stdlib.h>
using namespace std;
int*& wrong_getmem(int n) {
int* pa = (int *)calloc(sizeof(int),n);
return pa;
}
int main() {
int*& arr = wrong_getmem(10);
for (int i = 0; i < 10; i++)
arr[i] = i + 1;
for (int i = 0; i < 10; i++)
cout << arr[i] << " ";
return 0;
}
代码运行结果:
这样写风险是极大的, 因为函数返回的是临时栈帧中pa的别名,而pa在函数返回后就已经被销毁,也就是原本属于p的内存空间已经还给了操作系统。再利用别名访问到的pa,它的值很可能已经被其他程序覆盖。就算将arr改会指针类型:
int* arr = wrong_getmem(10);
依旧有风险,因为在给arr赋值以前,栈帧就已经销毁。
正确写法: