C++11中新增了一种引用:所谓的“右值引用”,当我们使用术语“引用”时,指的其实是“左值引用”。
引用: 为对象起了另外一个 名字,引用类型引用另外一种类型,通过将声明符写成&d的形式来定义引用类型,其中d是声明的变量名。
int ival = 1024;
int &refVal = ival;
// refVal 指向ival (是ival的另一个名字)
一般在初始化变量时,初始值会被拷贝到新建的对象中。程序把引用和它的初始值绑定在一起,一旦初始化完成,引用将和它的初始值对象一直绑定在一起。因为无法令引用重新绑定到另外一个对象,因此引用必须初始化。
int &refVal2;//报错:引用必须被初始化
refVal = 2;//把2赋給refVal指向的对象,此处即是赋给了ival
int ii = refVal;//与ii =ival执行结果一样
//正确: refVal3 绑定到了那个与refVal 绑定的对象上,这里就是绑定到ival上
int &refVal3 = refVal;//利用与refVal绑定的对象的值初始化变量i
int i = refVal; //正确: i被初始化为ival的值
因为引用本身不是一一个对象,所以不能定义引用的引用。
定义引用:允许在一条语句中定义多个引用,其中每个引用标识符都必须以符号&开头。
大部分引用的类型都要和与之绑定的对象严格匹配。而且,引用只能绑定在对象上,而不能与字面值或某个表达式的计算结果绑定在一起。
int i=1024,i2=2048;//i和i2都是int
int &r=i,r2=i2;//r是一个引用,与i绑定在一起,r2是int
int i3 = 1024, &ri = i3; // i3是int,ri是一个引用,与13绑定在一起
int &r3=13,&r4=i2;//r3和r4都是引用
指针:指针实现了对其他对象的间接访问,指针本身就是一个对象,允许对指针赋值和拷贝,而且在指针的生命周期内它可以先后指向几个不同的对象。指针无须在定义时赋初值。和其他内置类型一样,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。
定义指针:每个变量前面都必须有符号*
int *ip1,*ip2;//ipl和ip2都是指向int型对象的指针
double dp, *dp2; // dp2 是指向double型对象的指针,dp是double型对象
获取地址:指针存放某个对象的地址,要想获取该地址,需要使用取址符(&)。指针的类型大多要和它所指向的对象严格匹配。
int *P = &ival; // P存放变量ival的地址,或者说p是指向变量ival的指针
double dval;
double *pd = &dval; // 正确:初始值是double型对象的地址
double *pd2 = pd;//正确:初始值是指向double对象的指针
int *pi = pd;//错误:指针pi的类型和pd的类型不匹配
pi = &dval;//错误:试图把double型对象的地址赋给int型指针
指针值:
1.指向一个对象。
2.指向紧邻对象所占空间的下一个位置(试图访问此类指针对象的行为不被允许)。
3.空指针,意味着指针没有指向任何对象(试图访问此类指针对象的行为不被允许)。
4.无效指针,也就是上述情况之外的其他值。(试图拷贝或以其他方式访问无效指针的值都将引发错误。编译器并不负责检查此类错误,和使用未经初始化的变量是一样的,访问无效指针的后果无法预计。)
访问对象:使用解引用符(操作符*)来访问该对象,对指针解引用会得出所指的对象,因此如果给解引用的结果赋值,实际上也就是给指针所指的对象赋值:
int ival = 42;
int *p = &ival; // p存放着变量ival的地址,或者说p是指向变量ival的指针
cout << *p;//由符号*得到指针p 所指的对象,输出42
*p=0; //由符号*得到指针p所指的对象,即可经由p为变量ival赋值
cout<<*p;//输出0
空指针:
生成空指针的方法:
int *p1 = nullptr;//等价于int *pl = 0;
int *p2 = 0;//直接将p2初始化为字面常量0
//需要首先#include cstdlib
int *p3 = NULL;//等价于int*p3=0;
nullptr 种特殊类型的字面值,它可以被转换成任意其他的指针类型,名为NULL的预处理变量。预处理变量不属于命名空间std,它由预处理器负责管理,因此我们可以直接使用预处理变量而无须在前面加上std::。当用到一个预处理变量时,预处理器会自动地将它替换为实际值,因此用NULL初始化指针和用0初始化指针是一样的。在新标准下,现在的C++程序最好使用nullptr,同时尽量避免使用NULL。赋值,这个变量在头文件cstdlib中定义,它的值就是0。
把int变量直接赋给指针是错误的操作,即使int变量的值恰好等于0也不行。
int zero = 0;
pi = zero;//错误:不能把int变量直接赋给指针
赋值及其他操作: 给指针赋值就是令它存放一个新的地址,从而指向一个新的对象。
int i= 42;
int *pi = 0;// pi 被初始化,但没有指向任何对象
int *pi2 = &i;// pi2被初始化,存有i的地址
pi2 = 0;//现在pi2不指向任何对象了
如果指针的值是0,条件取false: 任何非0指针对应的条件值都是true。对于两个类型相同的合法指针,可以用相等操作符(=)或不相等操作符(!=) 来比较它们,如果两个指针存放的地址值相同(都为空、都指向同一个对象, 或者都指向了同一一个对象的下一地址),则它们相等,反之它们不相等。
void*指针:void*是一种特殊的指针类型,可用于存放任意对象的地址。不能直接操作void*指针所指的对象,拿它和别的指针比较、作为函数的输入或输出,或者赋给另外一个void*指针。以void*的视角来看内存空间也就仅仅是内存空间,没办法访问内存空间中所存的对象。
double obj = 3.14,*pd = &obj;//正确: void*能存放任意类型对象的地址
void *pv = &obj;// obj 可以是任意类型的对象
指向指针的指针:指针是内存中的对象,像其他对象一样也有自己的地址,因此允许把指针的地址再存放到另-一个指针当中。通过*的个数可以区分指针的级别。也就是说,** 表示指向指针的指针,***表示指向指针的指针的指针,以此类推。
int ival = 1024;
int *pi = &ival; // pi指向一个int型的数
int **ppi=π//ppi指向一个int型的指针
指向指针的引用:
int i= 42;
int *p;// p是一个int型指针
int *&r = p;// r是一个对指针p的引用
复合类型的声明:
//主是一个int型的数,p是一个int型指针,r是一个int型引用
inti=1024,*p=&i,&r=i;
int* p1, p2; // p1 是指向int的指针,p2是int