跳转至

指针与引用

变量、值和地址

int a = 10;
cout << a << '\n';  // 值,10
cout << &a;         // a的地址

地址,可以理解成变量在内存中的“门牌号”。&a 表示取 a 的地址。

地址的具体显示由运行环境决定,不需要背,也不要认为每次运行都一样。

指针,保存地址

int a = 10;
int *p = &a;

p 是一个指向 int 的指针,保存了 a 的地址,也就是p 指向 a。

写法 表示什么
a 变量a,读取它得到10
&a a的地址
p 指针变量,里面保存a的地址
*p p指向的对象,这里就是a

p 与 *p,不是一回事。 一个保存地址,一个访问指向的对象。

通过指针读写数据

*p 叫作解引用,找到指针所指向的对象。

int a = 10;
int *p = &a;

cout << *p << '\n'; // 输出10

*p = 20;

cout << a; // 输出20

通过 *p 修改的,就是 a。

指针可以改变指向。

int a = 10, b = 20;
int *p = &a;
p = &b;

*p = 30; // 修改的是b,a还是10

p = &b 是换地址,*p = 30 是改数据,别混了。

指针的定义与初始化

int *p = nullptr;
char *q = nullptr;
double *r = nullptr;

指针也分类型。这里的 p、q、r,分别用来指向 int、char、double。

nullptr 表示空指针,暂时没有指向对象。

普通局部指针,不初始化,就不能直接使用。

int *p;
// *p = 10; // 错误:p没有指向一个确定、有效的int对象

空指针也不能解引用。要先让它指向仍然有效的对象,再通过它读写数据。

引用,给变量起别名

int a = 10;
int &b = a;

b = 20;

cout << a; // 输出20

b 是 a 的另一个名字。它们表示同一个对象,不是复制出两份数据。

定义这里的引用变量时,就要绑定对象。

int &b; // 错误:没有说明b是谁的别名

引用不能改绑

int a = 10, b = 20;
int &r = a;

r = b;

这句话是把 b 的值赋给 a。执行后 a 变成 20,r 仍然是 a 的别名。

再修改 r,改的仍然是 a,不会改成操作 b。

指针与引用的区别

对比 指针 这里的引用
保存、表示什么 指针变量保存地址 引用是已有对象的别名
访问原对象 用 *p 直接用引用名
能否改为指向另一对象 可以修改指针里的地址 绑定后不能改绑
能否暂时没有对象 可以设为 nullptr 定义引用变量时就要绑定

是否需要额外存储来实现引用,是实现细节,不用把“引用一定不占空间”当成规则。

* 与 &,看出现的位置

写法 含义
int *p 定义指针
*p 解引用
&a 取地址
int &b = a 定义引用

同一个符号,放在定义和表达式里,意思可能不同。前面学过的乘法、按位与,也要结合上下文看。

常见错误

一个星号,不会让后面所有名字都变成指针。

int *p, q; // p是指针,q是int

初学时,指针一个一个定义,容易看清楚。

指向的对象已经失效,还继续使用。

局部变量离开作用范围后,原来指向它的指针和引用,就不能再拿来访问它。

引用不是普通复制。

int b = a; 得到独立变量,int &b = a; 才是给 a 起别名。