当前位置:编程学习 > C/C++ >>

进一步了解const指针

问题
今天群里有人发了个问题,问题如下:
第一个赋值可以,为什么第二个不行
[cpp]  
int * x = NULL;  
int const * y = NULL;  
y = x;  
  
int ** z = 0;  
int const ** n = 0;  
n = z  
 
当时我懵了一下,随即想到可能是int const **的问题,便把代码改成:
[cpp] 
int ** z = 0;  
int * const * n = 0;  
n = z;  
 
编译通过,以为解决了问题,想也没想,便发回给提问者。
殊不知,提问者问了好几个问题后,我又懵了,-_-!
这个const是属于那一边的?
可以是
[cpp]  
int (* const) * n = 0;  
 
那么n就是一个指向(int * const)的int指针
 
也可以是
[cpp]  
int * (const *) n = 0;  
 
那么n就是一个指向(int *)的const int 指针
 
后来提问者发了书里面的一句话:
如果const和(或)volatile关键字后面紧跟类型说明符(如int, long等),它作用于类型说明符,在其他情况下,const和(或)volatile关键字作用于它左边紧邻的指针星号。
本人觉得这句话不够确切,一般情况下,我们会把代码写成:
[cpp]  
const int * p;  
 
这和书中描述的一致,const 此时作用于int。但我们也有另外一种写法
[cpp]  
int const * p;  
 
虽然大家都知道这个const 必定作用于int的,但按照那句话的方法,const找不到作用的地方了。
好吧,这有点钻牛角了。既然是从书中出来的,还是得用代码来证明一下。
 
试验
回归到顶部问题,其实就是类型匹配问题,如果类型不匹配,那么编译就会报错,所以通过编译器(VS2010)来作为我们的裁判,const到底是作用于谁。
先铺好两个必须的变量:
[cpp]  
int * p_to_v_1 = new int(1);;  
int * p_to_v_2 = new int(2);  
 
第一试验
[cpp] 
int * * ppTest1 = &p_to_v_1;  
ppTest1 = &p_to_v_2;  
*ppTest1 = p_to_v_2;  
**ppTest1 = 10;  
这个应该理解上没有多大的问题,所以不解释。
编译通过,没报任何错误,结论:
*ppTest1也是int * 类型。
**ppTest1是int类型。
 
第二试验
[cpp] 
int const * * ppTest2 = &p_to_v_1;  
ppTest2 = &p_to_v_2;  
*ppTest2 = p_to_v_2;  
**ppTest2 = 10;  
这个比较简单,ppTest2指向的是int const *的指针,所以第三个**ppTest2的赋值编译器报错:表达式必须是可修改的左值。
*ppTest2也是int const * (或const int *)类型。
**ppTest2是const int 类型,不可改变,所以赋值时出错。
 
第三试验
[cpp] 
int * const * ppTest3 = &p_to_v_1;  
ppTest3 = &p_to_v_2;  
*ppTest3 = p_to_v_2;  
**ppTest3 = 10;  
const 来到两个星号中间,那么就是上面我遇到的问题了。
编译器此时报错是 *ppTest3 = p_to_v2; 这行代码,错误是:表达式必须是可修改的左值。
p_to_v2是指针变量,那么*ppTest3就是指针常量
*ppTest3是int * const类型。(印证了书中那句话)
**ppTest3那一行没报错,那么**ppTest3就是int类型
 
第四试验
[cpp]  
int * * const ppTest4 = &p_to_v_1;  
ppTest4 = &p_to_v_2;  
*ppTest4 = p_to_v_2;  
**ppTest4 = 10;  
报错的是“ppTest4 = p_to_v2;”这行,错误信息和上面例子一样,那么ppTest4就是一个指向指针的指针常量,ppTest4是不可更改的。
 
第五试验
[cpp]  
int const * const * ppTest5 = &p_to_v_1;  
ppTest5 = &p_to_v_2;  
*ppTest5 = p_to_v_2;  
**ppTest5 = 10;  
有了前面的基础,应该很容易判断这里报错的是哪个。
没错,第3行和第4行错误,*ppTest5是指针常量,**ppTest5是常量。
 
第六试验
[cpp]  
int * const const * ppTest6 = &p_to_v_1;  
ppTest6 = &p_to_v_2;  
*ppTest6 = p_to_v_2;  
**ppTest6 = 10;  
这个定义看起来有点奇怪,虽然会有编译警告,但是可以通过的。
报错的只有第3行(*ppTest6 = p_to_v_2;),因为*ppTest6是指针常量。
为什么第2行不报错呢?ppTest6是指向指针常量的指针,&p_to_v_2的结果又是指向指针变量的指针。
因为这个赋值的道理就如const int * 类型可以被int *类型赋值一样(如函数void f(const int * cp)中的参数,f被调用时,传入的参数可以是const int*,也可以为int *),一个是指向int常量的指针,一个是指向int变量的指针。
这里的定义(int (* const) (const *) ppTest6 )还有个地方需要注意一下,刚才说了,ppTest6是指向指针常量的指针;而刚好,*ppTest6又是指针常量,那这个定义就相当于
[cpp]  
int * const * ppTest6   
 
第七试验
[cpp]  
int * const * const ppTest7 = &p_to_v_1;  
ppTest7 = &p_to_v_2;  
*ppTest7 = p_to_v_2;  
**ppTest7 = 10;  
2和3行报错,ppTest7是常量,*ppTest7也是。
 
第八试验
[cpp]  
int const * const * const ppTest8 = &p_to_v_1;  
ppTest8 = &p_to_v_2;  
*ppTest8 = p_to_v_2;  
**ppTest8 = 10;  
这个2、3、4都报错,应该不用怎么解释了吧。。。
 
总结一下,刚才那句话大部分还是对的,就差了我刚才提到的那一点,嘿嘿。
如果const和(或)volatile关键字后面紧跟类型说明符(如int, long等),它作用于类型说明符,在其他情况下,const和(或)volatile关键字作用于它左边紧邻的指针星号。
 
解决问题
刚才说明了const在不同位置所起的不同作用,现在回过头来看原先的问题:
[cpp]  
int * x = NULL;  
int const * y = NULL;  
y = x;  
  
int ** z = 0;  
int const ** n = 0;  
n = z  
现在来看这些指针,应该比较明确:
z就是指向int *的指针;
而n就是指向const int *的指针;
n和z最终指向类型(一个是int, 一个是const int)是不一样的,所以赋不了值。
就如以下代码
[cpp]  
int * x = NULL;  
int * const y = NULL;  
y = x;  
 
补充:软件开发 , C++ ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,