关于const限定的字符指针

来源:互联网 发布:aws java sdk sns 编辑:程序博客网 时间:2024/05/22 09:47
 

一、 可能的组合

(1) const char *p

(2) char const *p

(3) char * const *p

(4) const char **p

(5) char const **p

(6) char * const  *p

(7) char ** const p

当然还有在(5)、(6)、(7)中再插入一个const的情况,不过分析了以上7种,其它的就可类推了!

 

二、理解助记法宝:

1. 关键看const修饰谁

2. 由于没有const *的运算,若出现const *的形式,则const实际上是修饰前面的

比如:char const *p, 由于没有const *运算,则const实际上是修饰前面的char, 因此char const *p 等价于 const char *p,也就是说上面7种情况种,(1)和(2)等价。同理,(4)和(5)等价。在(6)中,由于没有const*运算,const实际上修饰的是前面的char *,但不能在定义时转换写成const (char *) *p,因为定义在“()”中是表示函数。

三、深入理解7中组合

0. 程序在执行是为其开辟的空间皆在内存(RAM)中,而RAM里的内存单元是可读可写的;指针只是用来指定或定位要操作的数据的工具,用来读写RAM里内存单元的工作指针。若对指针不加任何限制,程序中一个指针可以指向RAM中的任意位置(出了系统敏感区,如操作系统内核所在区域)并对其指向的内存单元进行读和写操作(由RAM的可读可写属性决定);RAM里内存单元的可读可写属性不会因为对工作指针的限定而变化(见下面的第4点),而所有对指针的各种const限定说白了只是对该指针的读写权限(包括读写位置)进行了限定。

1. char *p: p是一个工作指针,可以用来对任意位置(非系统敏感区域)进行读操作和写操作,一次读写一个字节(char占一个字节存储单元)。

2. const char *p 或者 char const *p(因为没有const char *p运算,因此const修饰的还是前面的char):可以对任意位置(非系统敏感区域)进行“只读”操作。

3. char *const p (const修饰的是p):这能对“某个固定位置”进行读写操作,并且在定义p时就必须初始化(因为在后面不能执行“p=... “ 的操作,因此就不能在后面初始化,因此这能在定义是初始化)。 (”某个固定的位置“是相对于char *p来说所限定的内容)

可以总结以上3点为:char *p中的指针p通常是”万能“的工作指针,而(2)和(3)只是在(1)的基础上加了些特定的限制,这些限制在程序中并不是必须的,只是为了防止程序员的粗心大意而产生事与愿违的错误。

另外,要明白”每块内存空间都可有名字;每块内存空间内容皆可变(除非有所限制)“。比如函数里定义的char s[] = "hello",事实上在进程的栈内存里开辟了6个变量共六个字节的空间,其中6个字符变量的名字分别为:s[0]、s[1]、s[2]、s[3]、s[4]、s[5]、s[6] (内容是'\0')。

{

待验证:还有一个4字节的指针变量s。不过s是”有所限制“的,属于char * const 类型,也就是前面说的(3)这种情况,s一直指向s[0],即(*s == s[0] == 'h',可以通过*s = 'k' 来改变s所指向的s[0]的值,但不能执行(char *h = ”aaa“;  s = h; 来对s另外赋值。

}

4. 上面的(2) 和(3)只是对p进行限定,没有也不能对p所指向的空间进行限定,对于"char s[] = "hello"; const char *p = s; " 虽然不能通过 *(p+1) = 'x' 或者

p[i] = 'x' 来修改数组元素 s[0] ~ s[4] 的值,但可以通过 *(s+1) = 'x' 或者 s[i] = 'x' 来修改原数组元素的值——RAM里内存单元的可读可写属性不因对工作指针的限定而改变,而只会因对其本身的限定而改变。如const char c = ‘A’, c是RAM里一个内存单元(8字节)的名字,该内存单元的内容只可读,不可写。

5. const char **p 或者 char const **p: 涉及两个指针p 和 *p。 由于const 修饰char, 对指针p 没有任何限定,对指针*p 进行了上面情况(2)的限定。

6. char * const *p: 涉及两个指针p 和 *p。 由于const修饰前面的char *, 也就是对p所指向的内容*p进行了限定(也属于前面的情况(2))。 而对*p来说,由于不能通过 " **p = ... " 来进行另外赋值,因此属于前面的情况(3)的限定。

7. char ** const p: 涉及两个指针p 和 *p, const 修饰p, 对p进行上面情况(3)的限定,而对*p没有任何限制。

四、关于char **p、 const char **p的类型相容性问题

1. 问题

char *p1; const *p2 = p1;  //合法

char **p1; const char **p2 = p2; // 不合法,会有警告warning: initialization from incompatible pointer type

char **p1; char const **p2 = p1; // 不合法,会有警告warning: initialization form incompatible pointer type

char **p1; char * const *p2 = p1; //合法

2. 判断规则

明确const修饰的对象! 对于指针p1 和 p2,若要使得 p2 = p1 成立,则可读做

p1是指向X类型的指针,p2是指向“带有const限定”的X类型的指针“。

char *p1; const *p2 = p1; // 合法:p1是指向(char)类型的指针,p2是指向”带有const限定“的(char)类型的指针。

char **p1; const char **p2 = p1; //不合法:p1是指向(char*)类型的指针,p2是指向((const char) *)类型的指针。

char **p1; char const **p2 = p1; // 不合法:与上等价。

char **p1; char * const *p2 = p1; //合法:p1是指向(char *)类型的指针,p2是指向”带有const限定“的(char *)类型的指针。

五、其他

1. 含有const 的单层或双层指针的统一读法:

p是一个指针,是一个[“带有const限定”的] 指向 [“带有const限定”的] X类型的指针“。

2. 定义时const修饰的对象是确定的,但不能再定义时加括号,不然就和定义时用”( )“表示的函数类型想混淆了!因此定时时不能写 (char *) const *p或者 (const char) **p。