间接访问的方式:引用+指针。
1. 引用
一句话总结:已存在对象的别名,且类型严格一致,至死不渝。
1.1 已存在对象(绑定时)
- 已存在:定义时,必须初始化
//形式1:变量
int a = 2;
int &b = a;
//形式2:函数入参
int a = 2;
int fun(int &b){}
fun(a);
- 对象:绑定时,被绑定的不能是常量
//错误:绑定时不能为常量
int &b = 2;
//正确
int a = 0;
int &b =a; //绑定时为变量
b = 2; //这里已经绑定完了,已经是代表变量a了
####1. 2 别名(绑定后)
- 代表替换:绑定之后,就可以换成原来的对象在那个位置
//绑定
int a = 2;
int &b = a;
//代表形式1:
b = 4; //相当于a = 4;
//代表形式2:
int &c = b; //相当于int &c = a;
- 不占内存空间:绑定之后,只是一个代表符号
//下列三行一共占用了两个int的内存大小(a)和(c)
int a = 2;
int &b = a;
int c = 4;
1.3 类型严格一致(绑定时)
- 引用和被绑定的对象的类型必须严格一致
int a = 2;
double &b = a;//错误:类型不一致
1.4 至死不渝(绑定后)
- 一般在初始化变量时,初始值会被拷贝到新建的对象中,但是在定义引用时,程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用。
- 一旦初始化完成,引用将和它的初始值对象就一直绑定在一起。
- 因为无法令引用重新绑定到另外一个对象,因此引用定义时必须初始化。
2. 指针
2.1 例子
//
2.2 指针值
- 指向一个对象
- 指向紧邻对象所占空间的下一个位置
- 空指针,意味着指针没有指向任何对象
- 无效指针,上述之外的其他值
2.3 指针操作
- 赋值:
不赋值:函数外设置为0,初始化,但未指向任何对象;函数内,未定义,比较危险;
赋值常数;
赋值变量的地址;
赋值其他指针;
int i= 42;
int *p1 = 0; //初始化了,但未指向任何对象
int *p2 = &i; //初始化了,指向变量i
int *p3; //如果在块内,该值无法确定
p3 = p2;
p2 = 0;
注意:
有没有赋值:指针也是变量,有没有初始化,相当于看该指针变量是不是已经赋值了。 如果显示的赋值,那就是初始化了;如果没有赋值,再看是不是在块之外,外的默认赋值为0,内默认没有赋值,也就是没有初始化。
有没有赋合法的值:至于有没有指向对象,需要看已经初始化的值是多少。如果是0,那就没有指向任何对象;否则,指向代表的地址的对象。
- 判断:
前提:已经赋值,且是合法值
与其他变量一样,指针内的值为0–假;非零–真;
int i= 42;
int *p1 = 0; //初始化了,但未指向任何对象
int *p2 = &i; //初始化了,指向变量i
if(p1){} //假
if(p2){} //真
对比:
两个指针相等=> 两个指针内存的地址相同都为空;
都指向同一个对象;
都指向同一个对象的下一个地址;
两个指针不等=> 两个指针内存的地址不同空指针:
不指向任何对象;
用一个指针前一定要判空;
生成空指针的方法:赋值常量0,不能赋值变量0
//正确用法:赋值常量0
int *vp1 = nullptr; //推荐用法,相当于赋值0
int *vp2 = 0; //
int *vp3 = NULL; //包含#include cstdlib
//错误用法:赋值变量0
int a = 0;
int *vp4 = a; //错误!!!
- void* 指针:
特点:
可以存放任意类型的指针;
不能直接操作该指针,必须强转为对应的类型;
可作为函数的输入和输出;
//例子
3. 指针
3.1 引用和指针的区别
类型 | 是否为对象 | 必须赋处初值 |
---|---|---|
引用 | no | yes |
指针 | yes | no |
本质:
引用:因为绑定原对象,所以自己不是对象;因为不能转换指向,所以必须赋初值;
指针:与普通变量一样
3.2 引用和指针的复合用法
- 指向指针的引用
int i = 42;
int *p;
int *&r = p;//r是一个对指针p的引用
r = &i; //相当于p = &i;
*r = 43; //相当于*p = 43;
注意:
int & r = p;先认定是一个引用,然后类型是int ,然后改引用绑定的对象是指针p,绑定后用p理解就好。
- 指向引用的指针:不存在
因为引用不是对象,而指针必须指向一个对象,所以没法创造出来!!!