上节说到,变量名实际上是一段连续存储空间的别名。很显然我们可以将其命名为其它名字,就像我们有乳名、小名一样。
C++引入了引用的概念。
#include
int main(int argc, char *argv[])
{
int original = 1;
int& new_name = original;//c语言无引用的概念,用gcc会编译报错。
new_name = 2;
printf("original = %d, new_name = %d\n", original, new_name);
printf("&original = %p, &new_name =%p\n", &original, &new_name);
return 0;
}
上面程序中,int& new_name = original; 用original别名叫new_name,当new_name赋值后,对于的存储空间的值也会变化,故original 的值和new_name值一样。相应的,他们的内存地址打印也相同,如下图:
#include
//指针实现交换函数
void swap1(int* pa, int* pb)
{
int c = *pa;
*pa = *pb;
*pb = c;
}
//引用实现交换函数
void swap2(int& a, int& b)
{
int c = a;
a = b;
b = c;
}
int main(int argc, char *argv[])
{
int var_1 = 8;
int var_2 = 10;
swap1(&var_1, &var_2);
printf("after swap1, var_1 = %d, var_2 = %d\n", var_1, var_2);
swap2(var_1, var_2);
printf("after swap2, var_1 = %d, var_2 = %d\n", var_1, var_2);
return 0;
}
上面程序中,引用实现的交换函数可读性更好。
swap1(&var_1, &var_2); 如果不看函数实现,像是交换两个变量的地址。
swap2(var_1, var_2); 从函数写法,像是交换两个变量。不像指针可读性差。
#include
int main(int argc, char *argv[])
{
int a = 8;
const int& b = a;//变量a没有只读属性,当前只有变量b才有只读属性。
//b = 10; //打开这里,报错 error: assignment of read-only reference ‘b’
a = 20; //原来的变量还是可以赋值,不拥有只读属性
printf("a = %d, b = %d\n", a, b);
int *p = (int*)&b;
*p = 10;
printf("a = %d, b = %d\n", a, b);
return 0;
}
#include
int main(int argc, char *argv[])
{
const int& a = 8; //这里编译器会为这个常量分配存储空间。去掉const 编译器会报错 cannot bind non-const lvalue reference of type ‘int&’ to an rvalue of type ‘int’
int *p = (int *)&a;
*p = 10;//改变常量空间的地址内容
printf("a = %d\n", a);
return 0;
}
引用有自己的存储空间吗?下面通过一个实例来验证。
#include
struct C
{
int& a;//等价于 int* const a;
int& b;//等价于 int* const b;
};
int main(int argc, char *argv[])
{
printf("sizeof(C) = %ld\n", sizeof(C));
return 0;
}
两个int型引用组成的结构体,打印的正好是2个int型变量的长度,从编译器行为来看,引用有自己的大小。
下面再用一个例子来说明引用有自己的存储空间:
#include
struct T
{
int& a;
int& b;
int& c;
};
int main(int argc, char *argv[])
{
int a = 1;
int b = 2;
int c = 3;
T va = {a, b, c};
printf("&a = %p\n", &a);
printf("&b = %p\n", &b);
printf("&c = %p\n", &c);
printf("&va = %p\n", &va);
printf("sizeof(va) = %ld\n", sizeof(va));
return 0;
}
从打印结果来看,引用a,b,c都有自己的独立存储空间,va变量的空间为24字节,变量与变量内部的引用在内存上也是独立的。
#include
int& f1()
{
static int a = 8;
return a;//返回静态局部变量a的内存空间,f1()函数作为该内存空间别名
}
int& g1()
{
int b = 6;
return b;//返回局部变量b的内存空间,f1()函数作为该内存空间别名
}
int main(int argc, char *argv[])
{
int& c = f1();//返回静态局部变量a的存储空间别名给C
int& d = g1();//局部变量b内存空间别名,给到引用d. d代表局部变量b的内存空间。
f1() = 10;//f1() 作为静态局部变量a的别名,然后给内存空间赋值10.相当于给静态局部变量赋值为10.
printf("c = %d\n", c);
printf("d = %d\n", d); //打印被释放的空间别名值,出现段错误。
printf("f1() = %d\n", f1());//去除掉上一行语句后,这里打印10.
return 0;
}
当引用返回的是局部变量时,局部变量所在的函数运行完成,会释放掉该局部变量,而我们去访问 被释放的引用存储空间时,会出现不可控的情况,这段内存有可能被系统回收给其他变量使用。
在g++上,printf(“d = %d\n”, d); 编译器发生了警告,当运行程序时,访问了被释放的存储空间别名,出现段错误。某些编译器和平台上,会打印出随机值。
回答上一节的问题,C++对三目运算符做了什么?
在C++中不允许定义引用数组 Type& array[10],为什么?
如何定义一个数组的应用?如何定义一个函数的引用?
数组引用和数组指针有什么区别?函数引用和函数指针又有什么区别?