从char**无法赋给 const char**的原因,谈谈const限定符

作者:gfree.wind@gmail.com
博客:blog.focus-linux.net   linuxfocus.blog.chinaunix.net
 
 
本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
======================================================================================================
今天同事发了一个问题给我,说可以将char *变量赋给const char *变量,那么为什么char **不能赋给const char**呢?

看示例:
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>

  4. int main(void)
  5. {
  6.     char *p =NULL;
  7.     const char *cp = p;
  8.     char **pp= NULL;
  9.     const char **cpp = pp;


  10.     printf("%p %p %p %p\n", p, cp, pp, cpp);

  11.     return 0;
  12. }
编译:
[fgao@fgao-vm-fc13 test]$ gcc -g -Wall test.c
test.c: In function ‘main’:
test.c:10: warning: initialization from incompatible pointer type

测试结果确实是这样。下面说说原因。

其实warning已经明确的告诉了我们原因,之所以无法将char **赋给const char**,就是因为指针类型不同。那么为什么char *与const char*也是仅差了一个const,却可以呢。根本原因就在于const限定符究竟对起作用,以及指针的类型到底是什么。

首先,我们要看指针类型到底是怎样定义的。下面是C99标准中的定义
—A pointer type may be derived from a function type, an object type, or an incomplete
type, called the referenced type. A pointer type describes an object whose value
provides a reference to an entity of the referenced type. A pointer type derived from
the referenced type T is sometimes called ‘‘pointer to T’’. The construction of a
pointer type from a referenced type is called ‘‘pointer type derivation’’.
指针的类型取决于它指向的对象。

对于char *p,p的类型即为指向char的指针;const char * cp呢,这里的const修饰的是char,那么cp的类型即为指向const char的指针,也就是说cp并不是常量。也可以写为char const *cp,这时const仍然修饰的是char而不是cp。如果要定义一个常量指针,要写为char * const cp。

根据C99标准
For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to
the q-qualified version of the type; the values stored in the original and converted pointers
shall compare equal.
对于char *p和 const char *cp来说,根据上面的说明,是可以将p赋给cp的。


对于char **pp,pp的类型为指向char型的指针的指针;而const char ** cpp呢,根据前面关于const的说明,这里的const仍然是修饰的是char,那么cpp的类型为指向const char型的指针的指针。因此pp和cpp完全是两个不同的类型的指针,所以会产生warning。

是不是还是有点模糊啊,呵呵。那么下面,我再换一种说法,按照指针类型定义,指针的类型为指向类型T的指针。对于char **pp,其类型为指向类型T1的指针,T1的类型为指向char型的指针;而const char**cpp,其类型为指向类型T2的指针,T2的类型为指向const char型的指针。很明显,T1和T2是不同的指针类型,因此当把pp赋给cpp时,其类型不同导致产生warning。

不知道现在是否说清楚了呢?为了说的更清楚一些,我对上面的例子做一点小改动,来消除warning。
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>

  4. int main(void)
  5. {
  6.     char *p =NULL;
  7.     const char *cp = p;
  8.     char **pp= NULL;
  9.     char * const *cpp = pp;


  10.     printf("%p %p %p %p\n", p, cp, pp, cpp);

  11.     return 0;
  12. }
注意红色的那行,我移动了const的位置,从而改变了const修饰的内容。
编译:
[fgao@fgao-vm-fc13 test]$ gcc -g -Wall test.c
没有任何warning。

char * const *cpp 与 const char ** cpp,类型完全不同。后者前面已经说了。前者的类型为,指向char的常量指针的指针。也就是cpp的类型为指向常量T3的指针,而T3为指向char型的指针。这时cpp与pp的指向的类型仅限于限定符的不同,因此可以将pp赋给cpp。


我相信如果大家看到现在应该已经明白了为什么char **不能赋给 const char**了,并且通过这个例子,也对于const及其它限定符如volatile的修饰对象有了比较清楚的了解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值