首先,我们从const 说起。
const 有两种写法格式:const int n=20 和 int const n=20,它们相同吗?毫无疑问它们是相同的,这点务必记住。总之记住const 和 int 哪个放前面哪个放后面没关系,都是一样的。有了这个概念后,我们再来看const int *p 和int const *p,按照你的理解它们相同吗?其实它们也是相同的,还是那句话int 和const的前后位置不影响语义。好了,到现在我们明白了这一对的关系,那么int * const p 和它们相同吗?下面我们具体分析它们的语义。
一、const int *p的语义(当然int const *p也是一样的)
下面先看一个例子:
//********代码开始*******
int a=30;
int b=40;
const int *p=&a;
p=&b; //1、注意,p可以重新赋值一个新内存地址
b=80; //2、想想看,这里能用*p=80;来代替吗?当然不能
printf("%d",*pi);//3、输出是80
//********代码结束*******
语义分析:从这个例子中不难看出,p的值可以被修改,即它可以重新指向另一内存地址。但是不能通过*p来修改b的值。为什么呢?
首先,const修饰的是整个*p(注意我写的是*p不是p),所以*p是常量,是不能被赋值的(尽管p所指的b是变量,不是常量)。
其次,pi前没有被const修饰,所以p是指针变量,即能被赋值重新指向另一内存地址。
二、int *const p
下面还是先看一个例子:
//********代码开始*******
int a=30;
int b=40;
int *const p=&a;
//p=&b; 4、注意,p不能再这样重新赋值了,即不能再指向另一个新地址。
a=80; //5、想想看,这里能用*p=80;来代替吗?可以,这里可以通过*p修改a的值
printf("%d",*pi); //6、输出是80
//********代码结束*******
语义分析:从这段代码有没有发现,pi的值不能重新赋值修改了。它只能永远指向初始化时的内存地址。相反,这次你可以通过*p来修改a的值了。看下面的分析:
首先,p因为有了const的修饰,所以只是一个指针常量。也就是p不能修改了,即p不能重新赋值指向b了(如第4行)
其次,整个*p的前面没有const的修饰,也就是说*p是变量而非常量。所以我们可以通过*p来修改它指向内存a的值(如第5行的注释)
所以我们可以发现,p是指向int变量类型数据的指针常量。
最后总结两句:
1)如果const放在*p前,则不能修改的是*p(即不能这样 *p=80)而不是指p;
2)如果const放在p前,则p不能修改(即不能p=&b)
三、补充三种情况
情况一:int *p指向const int i常量的情况
//********代码开始*******
const int i=30;
int *p;
p=&i; //可行吗?不行,const int类型的i的地址是不能赋值给
//指向int类型地址的指针的,否则p岂不是可以修改i的值了吗
//********代码结束*******
我自己试了,虽然有警告,但是可行,而且可以利用p来修改i的值。如*p=100。(当然直接修改i的值肯定不行)所以为了避免我们可以把指针定义为const int *p
情况二:const int *p指向const int i常量的情况
//********代码开始*******
const int i=30;
const int *p;
p=&i; //两个类型相同,可以这样赋值。
//很显然,i的值无论是通过p还是i都是不能修改的
//********代码结束*******
情况三:用const int *const p申明的指针
//********代码开始*******
int i=30;
const int *const p;
p=&i; //你能想象p能够做什么操作吗?p值不能改,
//也不能通过p的值修改i的值。因为不管是*p还是p都是const的
//********代码结束*******