int a = 10;
int &b = a;
//对b进行操作的本质上是对a进行操作
//a和b指向同一片内存空间
b = 7;
//发现是引用,转换为 int* const ref = &a;
void func(int& ref){
ref = 100; // ref是引用,转换为*ref = 100
}
int main(){
int a = 10;
//自动转换为 int* const ref = &a; 指针常量是指针指向不可改,也说明为什么引用不可更改
int& ref = a;
ref = 20; //内部发现ref是引用,自动帮我们转换为: *ref = 20;
cout << "a:" << a << endl;
cout << "ref:" << ref << endl;
func(a);
return 0;
}
引用的本质为指针常量:只能修改指向的值,不能修改指向的地址
(1)指针常量(指针是常量):是一个指向不可改,值可改的指针
int a = 10, b = 20;
int * const p = &a;
*p = 30; // p指向的地址是一定的,但其内容可以修改
(2)常量指针(常量是指针):一个指向可改,值不可改的指针
int a = 10, b = 20;
const int *p = &a;
p = &b; // 指针可以指向其他地址,但是内容不可以改变
(谁先说谁不变,谁先说先写谁→*和p)
1.引用必须初始化
//int &b;是错误的,必须对引用进行初始化
2.引用在初始化后,不可以改变(引用是指针常量)
int &b = a;
b = c;
//这是允许的,因为这是赋值操作,,即将c的值赋值给b,而不是修改b的引用对象
//1. 值传递
void mySwap01(int a, int b) {
int temp = a;
a = b;
b = temp;
}
//2. 地址传递
void mySwap02(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
//3. 引用传递
void mySwap03(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
1.值传递中修改的是形参(传入函数的实参的拷贝),属于局部变量,只会修改swap函数中的a和b,但main函数中的a和b并不会修改
2.地址传递中传入的是main函数中的a和b的地址,修改swap函数中的a和b会导致main函数中的a和b发生改变
3.引用传递中swap函数的a和b是main函数中a和b的别名,修改swap函数的a和b会导致main函数的a和b发生改变
其中:函数里的a和main函数里的a处在不同的局部区域内,是不同的局部变量;不是引用名和函数名可以起的一样,只是参数的作用空间不一样,所以显得可以重名,但实际上在一个局部空间里不允许也没必要让引用和原变量重名
//返回局部变量引用
int& test01() {
int a = 10; //局部变量
return a;
}
//返回静态变量引用
int& test02() {
static int a = 20;
return a;
}
int main() {
//不能返回局部变量的引用
int& ref = test01();
cout << "ref = " << ref << endl;
cout << "ref = " << ref << endl;
//如果函数做左值,那么必须返回引用
int& ref2 = test02();
cout << "ref2 = " << ref2 << endl;
cout << "ref2 = " << ref2 << endl;
test02() = 1000;
cout << "ref2 = " << ref2 << endl;
cout << "ref2 = " << ref2 << endl;
system("pause");
return 0;
}
①全局区由操作系统分配释放,栈区通过编译器分配释放,堆区由用户分配释放
②如果是返回局部变量引用,则test01函数结束后返回main函数,第一次通过cout输出,系统保留该值;第二次则会被系统回收,访问越界
③如果是返回静态变量引用,则test02函数结束后返回main函数,可以通过cout输出该值
④返回引用可以作为左值:(因为此时返回的引用是该变量的别名)
(1)张三有1台手机,张三的小名叫伞伞,伞伞又去买了1台手机,所以张三/伞伞有2台手机
(2)把test02理解为是变量a的别名,此时取ref2为test02的别名,实质上都是返回值a(ref和test02都是a的别名)
①如果采用以下方式引用,是错误的;引用必须提供(指向)一个合法的地址,而10是常量
//int &ref = 10;
②如果采用以下方式引用,是正确的;编译器将会先申明一个变量(对程序员透明)来存储10,然后,用ref指向这个变量的地址(可以通过cout输出此地址)
//编译器先int temp = 10;
//再const int &p = temp;
const int &p = 10;
③如果要通过引用的方式传入参数,为了防止在函数中对参数进行修改,可以采用const的方式防止
(1)需要首先明确的是,形参改变实参这种情况只可能发生在地址传递或引用传递之中(值传递修改的是实参的拷贝)
(2)“防止形参改变实参”的意思是:在函数中可能会对形参的值进行修改;由于是引用传递,因此实参也会跟着改变(加了const后,在函数中对形参进行修改将会报错)
(3)引用传递可以有效减少内存占用(主要目的);如果采用值传递的方式,虽然改变形参并不会改变实参,但是会增加内存占用
//引用使用的场景,通常用来修饰形参
void showValue(const int& v) {
//v += 10;
cout << v << endl;
}
int main() {
//int& ref = 10; 引用本身需要一个合法的内存空间,因此这行错误
//加入const就可以了,编译器优化代码,int temp = 10; const int& ref = temp;
const int& ref = 10;
//ref = 100; //加入const后不可以修改变量
cout << ref << endl;
//函数中利用常量引用防止误操作修改实参
int a = 10;
showValue(a);
system("pause");
return 0;
}