(引用)
引用就是给对象起了另一个名字。(C++有左值引用和右值引用,这里是左值引用)
定义引用
int &refVal = ival; 引用必须被初始化。 初始化之后引用对象不能再引用别的对象。
int ival = 1024;
int &refVal = ival;
int &refVal2; //错误,引用必须被初始化
(1)定义引用时,是把引用和他的初始值绑定在一起,没有拷贝操作,因为引用不是对象。
(2)引用的类型要和他绑定的对象的类型严格匹配(有例外情况,后面会提到)
(3)引用只能绑定在对象上,不能绑定在某个字面值或者表达式的计算结果
引用即别名,不是对象,只是绑定的对象的另一个名字。对这个引用赋值就是对那个对象赋值。不能定义引用的引用,因为引用不是对象。
(指针)
指针是“指向”另外一种类型。
指针与引用的异同:
相同点:都实现了对其他对象的间接访问。指针类型要和它所指向的对象严格匹配,引用也是。(都有例外)
不同点:(1)指针本身是一个对象,引用不是。(2)指针允许在他的生命周期内先后指向几个不同的对象,引用不可以。(3)指针无需一定要在定义时赋初值,引用必须。
定义指针
int ival = 42;
int *p = &ival;//可以理解为定义一个int型指针p,存放ival的地址,&是取地址符
double dval;
double *pd = &dval;
double *pd2 = pd;
int *pi = pd; //错误,类型不匹配
pi = &dval; //错误,类型不匹配
指针的值只有4种可能:(1)空指针,不指向任何对象。(2)指向一个对象。(3)指向紧邻对象所占空间的下一个位置。如vector的end(),指向有效空间的边界,为内存构造一个左闭右开的区间。(4)无效指针,不能拷贝或其他方式访问,编译器不检查这种错误。解引用操作只适用于确实指向了某个对象的有效指针。
空指针
生成空指针的方法:
int *p1 = nullptr;
int *p2 = 0;
int *p3 = NULL; //NULL是预处理变量,在cstdlib中定义,值为0.
预处理器是运行于编译过程之前的一段程序。预处理变量不属于命名空间std,它由预处理器负责管理。C++中最好用nullptr,避免NULL。用到预处理变量时,预处理器会自动的将它替换为实际值,因此后两种初始化方式是一样的。但是不能直接把int值赋给指针。
int zero = 0;
pi = zero; //错误
void* 指针
可以用于存放任意对象的地址,对该地址中到底是什么类型的对象没有要求。
void*指针可以:和别的指针比较,作为函数的输入输出,赋给另外一个void*指针。
void*指针不可以:解引用。不能访问这个指针所指的对象。
复合类型
指向指针的指针
**表示指向指针的指针
int ival = 42;
int *pi = &ival;
int **pi = π
需要两次解引用。下面三个输出是一样的:
cout << ival << endl;
cout << *pi << endl;
cout << **pi << endl;
指向指针的引用
int i = 42;
int *p;
int *&r = p; //指向指针的引用。r是一个引用。
r = &i; //r是p的别名,所以给r赋值,就是让p指针指向i
*r = 0; //将i的值改为0
面对比较复杂的指针或引用的声明语句,从右向左读。离变量名最近的符号对变量的类型有直接的影响,因此r是一个引用。声明符的其余部分用以确定r引用的类型是什么。*表示引用的是一个指针。int表示是int型的指针。