常见的坑
&
和*
在不同的上下文里面其含义并不相同,因此完全可以当成不同的符号看待。int i = 42; int &r = i; // &在类型名后出现,是声明的一部分,表明r是一个引用 int *p; // *在类型名后出现,是声明的一部分,表明p是一个指针 p = &i; // &在表达式中出现,是取地址符 *p = 43; // *在表达式中出现,是解引用符 int &r2 = *p; // &是声明的一部分,*是解引用符
指针可以用
0
进行初始化成空指针,但是不可以用0
赋值。指针之间使用
==
来比较时,如果结果是true
,对应多种情况:- 都是空指针
- 都是同一个地址
- 都指向同一个对象
- 一个指针指向某一个对象,另一个指针指向另一对象的下一地址
必须要理解的点
引用和指针——都可以用于间接访问对象
引用 指针 复合类型 ✅ ✅ 表示符号 & * 含义 变量的别名 变量在内存中的地址 初始化和赋值时是否需要类型匹配 必须匹配(除常量引用) 必须匹配(除 void*和指向常量的指针) 是否需要初始化 必须初始化 无需初始化 可否重新绑定其他变量 不可以 可以 可否嵌套定义 不可以 可以 引用:
- 引用只能绑定在对象上,不能绑定在字面量或者表达式上。
- 引用只是原有对象的别名,并非对象,因此不可以定义引用的引用。
- 定义引用时并不开辟新的内存空间,因此不可以定义引用的指针。
指针:
指针本身就是一个对象,能执行的操作自由度远超过引用。
可以实现嵌套定义,即指针的指针。
可以实现指针的引用。
int i = 42; int *p; // p是int型指针 int *&r = p; // r是指针p的引用,从r开始自右向左读,&表明r是一个引用,引用的是指针,指针指向的类型是int r = &i; // r是p的别名,即给p赋值为i的地址,即令p指向i *r = 0; // r是p的别名,对r解引用即对p解引用,即将p所指向的地址处变量的值赋值为0
指针初始化和赋值时需要使用&运算符取得对象的地址。
指针值的情况:
- 指向一个对象。
- 指向紧邻对象所占空间的下一个位置。
- 空指针,没有指向任何对象。
- 无效指针,除上述情况之外。
对第 4 种无效指针的操作是未定义的,后果无法预计。
2、3 两种值虽然有效,但是因为没有指向任何对象,所以对其操作的后果同样无法预计。
void*
眼中内存空间仅仅是内存空间,并不能访问内存空间中的对象。
建议
初始化所有的指针,并且在对象定义完成之后再定义指向它的指针。
避免使用
0
和NULL
初始化空指针,应该使用nullptr
。在使用指针之前检查其是否为
nullptr
。记住赋值改变的永远是等号左侧的对象。
面对复杂的指针或引用的声明语句时,从变量名开始自右向左阅读来弄清楚其真实含义。