指针与引用的区别

最近在看C++Primer第五版,以前虽然竞赛一直用的C++,但是感觉自己学的不太深入,而且对于很多东西不求甚解,所以这次沉下心来好好看看这本C++经典,做一些相关的笔记。

引用

我们通过在变量名前添加&来定义一个引用类型。例如:

int val = 10;
int &refVal = val;

引用与它所指向的对象绑定到一起,引用并不是一个对象,所以其实引用就可以看作是一个变量的别名。我们对引用所进行的一些操作,其实都是作用在其绑定的对象身上的。引用在绝大部分情况下都必须与相同类型的对象进行绑定,而且引用不能与字面值或者是某个表达式的计算结果进行绑定。

int val = 10;
int &refVal = val;
refVal = 20; //其实这个赋值操作真正的作用对象是val,val=20
double &refVal2 = val; //错误,类型不匹配
int &ref = 10; //错误,不能与字面值进行绑定

有一个重要的点是,引用一旦与对象绑定,那么我们就不能再改变它,使其与其他对象绑定。正是因为这个规定,所以我们在定义引用的时候必须将其初始化,使其与某个对象进行绑定。

指针

指针一直都是学C/C++人士的一个噩梦,因为它极高的灵活性和复杂的操作,所以一不小心就会掉进自己挖的坑里。但是这个知识又是大家都绕不过的,所以我们还是得好好了解下,至少当其他的代码里面出现这些相关内容之后,我们应该能够看懂。

通过它的名字“指针”我们可以知道,这个东西是用来指向某个对象的。至少这点和引用有点类似,指针同样实现了对所指向对象的间接访问。

我们通过在变量名前添加*来定义一个指针类型。例如:

int *p1;
double *p2;

指针所做的操作是将所指向对象的地址保存,这样就实现了“指向”的功能。所以我们在给指针变量赋值的时候一定要将对象的地址赋给它。这个时候需要用到“取地址符”&,注意此时的&是取地址的意思,但是上面它也有引用的意思,我们要结合上下文来理解符号的具体意思。

int val = 10;
int *p;
p = &val; //将val变量的地址放在p指针中

如果我们要对它所指向的对象进行操作的时候,我们需要用到*(解引用符)。

int val = 10;
int *p;
p = &val;
*p = 20; //此时是将val的值赋为20

指针可以在定义的时候不进行初始化,而在之后进行初始化,并且指针可以更换自己指定的对象。与引用类似,在绝大多数情况下,我们指针所指向的对象的类型必须要与指针的类型保持一致。

double v = 2.5;
int val1 = 10, val2 = 20;
int *p; //在定义的时候不必要进行初始化
p = &val1; 
p = &val2; //指针指向另外一个对象
int *ptr = &v; //错误,类型不匹配

因为指针本身也是一个对象,它也有自己的地址,所以我们可以定义出指向指针的指针,同样还有指针的指针的指针...

int val = 10;
int *p = &val;
int **pp = &p; //指向指针的指针,注意声明符的写法
int ***ppp = &pp; //指向指针的指针的指针

我们还需要注意空指针的一些相关操作:

int *p1 = 0; //定义一个空指针
int *p2 = nullptr; //等价于上面的语句

//首先在代码中加入#include <cstdlib>
int *p3 = NULL; //同样是定义一个空指针

//但是我们需要注意,不能直接将变量的值赋给一个指针,哪怕该变量的值等于0也不可以
int val = 0;
int *p4 = val; //错误

引用与指针之间的主要区别

通过上面的讲解我们可以发现,虽然引用与指针同样都可以对某对象实现间接访问,但是还是有很多不同的。

  1. 一个最大的不同点就是:引用不是一个对象,所以它没有实际的地址。指针是一个对象,它有实际的地址,所以我们可以定义指向指针的指针,但是绝对不能定义指向引用的指针。
  2. 引用在其生命周期中不能改变所绑定的对象,但是指针可以在其生命周期内先后指向不同的对象。
  3. 引用在定义的时候必须进行初始化,而指针可以不必进行初始化(不推荐这种做法)。

References:

原文地址:https://www.cnblogs.com/yinzm/p/6510938.html