指针与引用¶
变量、值和地址¶
这句话表示:
- 定义了一个整型变量
a - 给它赋值为
10
从程序表面看,a 里存的是 10。
但从计算机内部看,变量并不是“飘在空中”的,它一定放在内存中的某个位置。
所以一个变量,实际上有两层信息:
- 值
- 地址
这里的地址,可以理解成变量在内存中的“位置编号”或者“门牌号”。
指针¶
指针是一个专门用来存放地址的变量。
普通变量存的是普通数据,比如整数、字符、实数。
而指针变量存的不是这些值,它存的是“某个变量所在的位置”。
这句话的意思是:
a是一个整型变量&a是a的地址p是一个指针变量p中存放的是a的地址
也可以用一句更直观的话来理解:
指针 p 指向变量 a。
指针的声明¶
指针也要分类型,
如果不知道那个地址里存的是哪种类型的数据,程序就无法正确理解那块内存里的内容。
引用¶
引用是一个已有变量的别名。
所谓“别名”,就是另一个名字。
它不是独立开辟出来的新变量,而是给原来的变量再起一个名字。
这句话表示:
a是一个整型变量b是a的引用b是a的另一个名字
所以此时:
a和b表示的是同一个对象- 改
a,b会跟着变 - 改
b,a也会跟着变
引用的声明¶
这表示 b 是 a 的引用。
引用在定义时就必须绑定到某个变量。
它不能只声明,不绑定。
引用和原变量的关系¶
引用不是复制,也不是重新存一份值。
它本质上还是在表示原来的那个变量。
所以可以把引用理解为:
同一个人有两个名字。
输出的都是同一个值。
如果再写:
那么 a 也会变成 20。
因为这里不是“把 20 赋给一个新变量”,而是“通过 b 这个名字去修改 a”。
指针与引用的核心区别¶
1、指针是变量,引用是别名¶
指针
指针本身是一个变量。
它有自己单独的存储空间,里面存的是某个地址。
引用
引用不是一个独立的新变量。
它只是已有变量的另一个名字。
2、指针存地址,引用直接代表原变量¶
指针
指针变量中保存的是地址,所以:
p表示地址*p才表示那个地址中的值
引用
引用没有“先存地址,再取值”这一层。
它直接就当原变量使用。
所以:
b直接就是原变量的别名- 不需要额外写
*
3、指针可以改变指向,引用一般不能改绑¶
这里是可以的,因为指针里存的是地址,地址可以换。
但引用不同:
此后 r 就一直是 a 的别名。
它不能再变成 b 的别名。
这也是引用和指针一个非常本质的差别。
指针的基本用法¶
1、取地址运算符 &¶
这里 &a 表示变量 a 在内存中的地址。
2、用指针保存地址¶
这里:
&a是a的地址p保存了这个地址
所以 p 指向 a。
这时候:
输出的是地址。
3、解引用运算符 *¶
当 * 出现在已经定义好的指针变量前面时,表示:
取出这个指针所指向地址中的值
例如:
这里:
p是地址*p是这个地址里的值
由于 p 里存的是 a 的地址,所以 *p 就表示 a 的值。
4、通过指针访问和修改数据¶
这里:
*p先访问到a的值- 再通过
*p = 20修改了a
所以可以理解成:
指针像一条线,先找到地址,再通过这个地址操作对应的数据。
引用的基本用法¶
1、定义引用¶
此时 b 是 a 的引用。
也就是说:
b就是aa也是b
它们是同一个对象的两个名字。
2、像普通变量一样使用引用¶
这里:
- 读取
b,就是读取a - 修改
b,就是修改a
所以引用最大的特点就是:
用起来像普通变量,但本质上不是一份新的数据。
3、引用必须在定义时初始化¶
这是正确的。
而下面这种写法不行:
因为引用不是独立变量,它必须一开始就说明“它是谁的别名”。
* 和 & 的含义¶
1、* 的两种常见含义:¶
第一种:声明指针
表示 p 是一个指向 int 的指针。
第二种:解引用
表示取出指针 p 所指向地址中的值。
所以同样要看场景:
- 放在定义里,表示“这是个指针”
- 放在表达式里,表示“取这个指针指向的值”
2、& 的两种常见含义¶
第一种:取地址
第二种:声明引用
表示 b 是 a 的引用。
所以要根据上下文判断:
- 放在表达式里,常表示取地址
- 放在类型后面,常表示引用
易错点¶
1、a、&a、p、*p 分别是什么
那么:
a是变量中的值&a是变量a的地址p是存放地址的指针变量*p是p指向地址中的值
最关键的两组关系是:
p = &a*p = a
2、指针变量和它指向的数据不是一回事
这里:
p自己是一个变量p里存的是地址*p才是这个地址里的值
所以不能把 p 和 *p 混为一谈。
3、引用不是拷贝
这不是说“把 a 的值复制给 b”。
而是说:
4、b 和 a 表示的是同一个变量
所以引用和普通赋值完全不是一回事。