初步理解:
指针即指针变量,其保存的是内存地址。可以使用指针实现对对象的间接访问,像其他的变量一样,可以不初始化,在块作用域内,将拥有一个不确定的值,可以改变指针的值,使其指向不同的内存空间。
一般形式:
一般来说,指针保存的是内存地址,想获得内存地址,需要使用取地址符&:
int i = 0;
int *p = &i; //p中保存的是变量i的地址值
由于引用不是对象,没有实际的地址,所有不能定义指向引用的指针。
和引用一样,一般来说,指针类型要和它所指向的对象的类型严格匹配。
指针访问对象:
如果指针指向了一个对象,可以使用解引用符*来访问对象。
float i = 0.0f;
float *p = &i; //定义一个指向i的指针
*p = 2.0f; //通过对p解引用的方式,对i赋值
空指针不指向任何对象,在试图使用一个指针之前,可以检查其是否为空,使用c++11的字面值nullptr可以得到空指针,其他的几种空指针方式:
int *p = 0; //直接初始化为字面值常量0
int *p1 = NULL; //需要#include cstdlib
int *p2 = nullptr; //常用方式
注意不能使用int变量给指针赋值,即使该变量的值刚好为0也不可以。
int i = 0;
int *p = i; //错误,不能将int赋值给指针
和引用的区别:
相同点的是都可以实现对象的间接访问,而在具体的实现上有很大不同,最大的区别就是,引用本身不是一个对象,一旦定义了引用,就不能再将其绑定到其他的对象上,以后的每一次使用都是在访问当初它绑定的那个对象。
指针本质上就是一个变量,其存放的值可以修改,也就是说,指针可以指向不同的对象,实现对不同对象的间接访问。
复合对象的理解:
定义多个变量的语句:
int i = 0 , &m = i, * p = &i;
对于上面的语句,i,m,p是变量名,int、int &、int *分别是其对应的类型。
对于下面的定义:
int i = 0;
int *p;
int *&r = p;
要理解r的数据类型,可以从右往左解析r,首先r是一个引用,其次他是一个绑定到指针的引用。
const和指针:
指针常量
指针指向的对象是一个常量,一般的表现形式为:
const int i = 0;
const int *p = &i;
和引用一样,这里的常量只是限定不能使用该指针改变指向的对象,对于其指向的对象到底是不是一个常量,这里是不太关心,所以下面的代码也是合理的:
int i = 0;
const int *p = &i; //合理
常量指针
指针是一个变量,所以可以将指针的值定义为常量,即该指针只能指向那个初始化的对象了。由于常量必须初始化,所以常量指针也必须初始化。
int i = 0;
int *const p = &i;//必须初始化,以后不能修改p的指向了
当然也可以定义如下的指针:
int i = 0;
const int * const p = &i;
指针的指向不能修改,也不能通过该指针修改其指向对象的值。对于其指向对象是不是一个常量,也是未可知的。
指向指针的指针:
由于指针本身就是一个变量,所以我们可以定义另外一个指针来指向当前指针:
int i = 0;
int *p = &i; //指向i的指针p
int **p1 = &p; //指向p的指针p1
理解p1,首先他是一个指针,其次他所指向的对象是一个int *的指针 int * *p1。其他的多级指针可以类比得到。