




已阅读5页,还剩3页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
const指针和指向const的指针 博客分类: C系列指向const对象的指针 指向const对象的指针就是一个指针,不能通过它来修改它所指向的对象的值。 声明方法:const int *p;const对象在初始化后是不允许对其值进行修改的,因此,我们不能用一个普通指针指向一个const对象,即下面的赋值会引起编译错误: const int i = 1; int *p = &i;否则的话,我们就可以利用普通指针来修改一个const对象的值,那么const也就毫无意义了。正确的方法是利用一个指向const对象的指针来获取const对象的地址: const int i = 1; const int *p = &i; char const *p = const char *p;这样,利用指向const对象的指针也是不能修改它所指向的const对象的值的。注意:1.指向const对象的指针本身不是const类型(这也是它与const指针的主要不同点),所以它可以指向另一个const对象2.指向const对象的指针可以被赋予一个非const对象的地址,但是此时试图通过此指针来修改对象的值的操作是非法的const指针 const指针就是一个指针,它本身就是const类型,所以将它初始化后不能再改变它的指向,即不能让它指向一个新的对象。声明方法:int *const p;/指向非const对象的const指针const int *constp;/指向const对象的const指针使用const指针不可以修改其地址值,但是const指针指向非const对象,就可以利用它修改它所指向的对象的值技巧: 如果指针名前紧邻的关键字为const,那么它就是一个const指针;如果声明指针所指向的对象类型前有const关键字,那么它就是一个指向cosnt对象的指针。补充: Bjarne在他的The C+ Programming Language里面给出过一个助记的方法:把一个声明从右向左读(这可能和我们平常习惯有所不同,需要特别注意)。 char * const cp; ( * 读成 pointer to ) cp is a const pointer to char ,亦即指针常量,cp值不可改变,但*cp,也就是cp所指对象能够改变。 const char * p; p is a pointer to const char,亦即指向常量的指针,所以p所指的对象不可改变。补:一、可能的组合: (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*p运算,因此const修饰的还是前面的char):可以对任意位置(非系统敏感区域)进行“只读”操作。(“只读”是相对于char *p来说所限定的内容) (3)char *const p(const 修饰的是p):只能对“某个固定的位置”进 行读写操作,并且在定义p时就必须初始化(因为在后面不能执行“p=.”的操作,因此就不能在后面初始化,因此只能在定义时初始化)。(“某个固定的位 置”是相对于char *p来说所限定的内容)可以总结以上3点为:char *p中的指针p通常是”万能”的工作指针,而(2)和(3)只是在(1)的基础上加了些特定的限制,这些限制在程序中并不是必须的,只是为了防止程序员的粗心大意而产生事与愿违的错 误。另外,要明白“每块内存空间都可有名字;每块内存空间内容皆可变(除非有所限)”。比如函数里定义的char s=hello;事实上在进程的栈内存里开辟了6个变量共6个字节的空间,其中6个字符变量的名字分别为:s10、s11、 s12、s13、s14、s15(内容是0)待验证:还有一个4字节的指针变量s。 不过s是“有所限制”的,属于char *const类型,也就是前面说的 (3)这种情况,s一直指向s0, 即(*s=s0=h),可以通过*s=k来改变s所指向的 s0的值,但不能执行(char *h“aaa”;s=h;)来对s另外赋值。 (4)上面的(2)和(3)只是对p进行限定,没有也不能对p所指向的空间进行限定,对于char s=hello;const char*p=s; 虽然不能通过*(p+i)=x或者pi=x来修改数组元素s0s4的值,但可以通过*(s+i)=x或者si=x来修 改原数组元素的值RAM里内存单元的可读可写属性不因对工作指针的限定而改变,而只会因对其本身的限定而改变。如const char cA,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=p1;/不合法,会有警告warning: initialization from incompatible pointer type char *p1;char const*p2=p1;/不合法,会有警告warning: initialization from 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。六、问题探讨(由于博文后的留言有字符数目限制,将回复移到这里)问题1(见博文后留言):讲解非常好,不过有个问题想探讨下: 例如: const char wang=wang; char *p; p=wang; 是错误的。 所以char *p中的P不能指向常变量。 (1)需要补充纠正。回复:你好!谢谢指正!我在ubuntu 10.04(gcc 4.4.3)下做了如下测试: /test_const.c #include int main() const char wang=wang; char *p; p=wang; p2=c; printf(p is %sn,p); return 0; 编译: gcc -o test_const test_const.c输出如下: test_const.c: In function main: test_const.c:17: warning: assignment discards qualifiers from pointer target type执行: ./test_const p is wacg结论:根据本博文中第四点相容性问题,将const型的wang赋值给p是不合法的。但编译器对其的处理只是警告,因此执行时通过p修改了只读区域的数据。这应该是该编译器处理不严所致后果,不知你用的什么编译器? 问题2回答/bbs/showthread.php?t=239058提到的问题在c语言里/ test.cint main() const char* s1 = test; char *s2 = s1; s2 = Its modified!; printf(%sn,s1);out: Its modified!;这样也可以吗? 照我的理解岂不是const限定符在c语言里只是摆设一个? 回复:(1)首先,以上代码编译时会出错warning: initialization discards qualifiers from pointer target type, 因为char *s2 = s1和问题1提到的一样,不符合相容规则。(2)输出结果是正确的,代码分析如下:int main() const char* s1 = test;/ 在只读数据区(objdump -h test后的.rodata区)开辟5字节存储test,并用s1指向首字符t。 char *s2 = s1;/ s2也指向只读数据区中“test”的首字符t。 s2 = Its modified!;/在只读数据区开辟15字节存储Its modified!,并将s2由指向t转而指向Its modified!的首字符I。 printf(%sn,s1);/ 从s1所指的t开始输出字符串test。(3) 总结:提问者的误区在于,误以为s2 = Its modified!是对“test”所在区域的重新赋值,其实这里只是将“万能”工作指针s2指向另外一个新开辟的区域而已。比如若在char *s2 = s1后再执行s22=a则是对“test”的区域进行了写操作,执行时会出现段错误。但这个段错误其实与const没有关系,因为“test”这 块区域本身就是只读的。为了防止理解出错,凡事对于对指针的赋值(比如s2 = Its modified!),则将其读做:将s2指向“Its modified!”所在区域的首字符。(4)额外收获:执行gcc -o test test.c后,“test”、“Its modified!”、%sn都被作为字符串常量存储在二进制文件test的只读区 域 (.rodata)。事实上,一个程序从编译到运行,对变量空间分配的情况如下:A。赋值了的全局变量或static变量=放在可执行文件的.data段。B。未赋值的全局变量或static变量放在可执行文件的.bss段。C。代码中出现的字符串常量或加了const的A放在可执行文件的.rodata段。D。一般的局部变量在可执行文件中不占空间,在该二进制文件作为进程在内存中运行时才为它分配栈空间。E。代码中malloc或new出的变量在可执行文件中不占空间,在该二进制文件作为进程在内存中运行时才为它分配堆空间。问题3:(待进一步分析)验证博文中 三(3)提到的是否为s分配空间,初步分析结果为:不分配!文中的s只是s0的地址的代号而已。#includeint main() int a=3; char s1 = test; int b=4; char s2 =test2; printf(the address of a is %un,&a); printf(s1 is %un,s1); printf(the address of s1 is %un,&s1); printf(the address of b is %un,&b); printf(s2 is %un,s2); printf(the address of s2 is %un,&s2); 输出结果:the address of a is 3213037836s1 is 3213037827the address of s1 is 3213037827the address of b is 3213037832s2 is 3213037821the address of s2 is 3213037821由结果可以看出,编译器做了些优化。七、其他相关经典文章转载王海宁,华清远见嵌入式学院讲师,对const关键字的理解/Column/Column311.htm 目前在进行C语言补习时,发现很多的同学对于const这个关键字的理解存在很大的误解。现在总结下对这个关键字理解上的误区,希望在以后的编程中,能够灵活使用const这个关键字。1、 const修饰的变量是常量还是变量 对于这个问题,很多同学认为const修饰的变量是不能改变,结果就误认为该变量变成了常量。那么对于const修饰的变量该如何理解那?下面我们来看一个例子:int mainchar buf4;const int a = 0;a = 10; 这个比较容易理解,编译器直接报错,原因在于“a = 10;”这句话,对const修饰的变量,后面进行赋值操作。这好像说明了const修饰的变量是不能被修改的,那究竟是不是那,那么下面我们把这个例子修改下:int mainchar buf4;const int a = 0;buf4 = 97;printf(“the a is %dn”,a);其 中最后一句printf的目的是看下变量a的值是否改变,根据const的理解,如果const修饰的是变量是不能被修改的话,那么a的值一定不会改变, 肯定还是0。但是在实际运行的结果中,我们发现a的值已经变为97了。这说明const修饰的变量a,已经被我们程序修改了。那 综合这两个例子,我们来分析下,对于第二例子,修改的原因是buf4的赋值操作,我们知道buf4这个变量已经造成了buf这个数组变量的越界访 问。buf数组的成员本身只有0,1,2,3,那么buf4访问的是谁那,根据局部变量的地址分配,可以知道buf4的地址和int a的地址是一样,那么buf4实际上就是访问了const int a;那么对buf4的修改,自然也修改了const int a的空间,这也是为什么我们在最后打印a的值的时候看到了97这个结果。那么我们现在可以知道了,const修饰的变量是不具备不允许修改的特性的,那么对于第一个例子的现象我们又如何解释那。第一个
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 离婚协议书上写的居住权
- 项目投资协议书合同范本
- 商品房买卖补充协议书
- 怎么拟协议书
- 木材买卖合同(CF-200-0114)绿色包装版
- 喜茶跨界活动策划方案
- 南宁团队管理咨询方案
- 协议书存款口子
- 零售业2025年预付卡安全管理协议
- 2025-2030云计算服务市场竞争格局及客户需求变化研究报告
- 2025年辅警考试真题及答案
- 2025-2026学年统编版五年级上册语文第二单元过关试卷附答案(三套)
- 2025年农村土地租赁协议(合同样本)
- 2025年固态变压器(SST)行业研究报告及未来发展趋势预测
- 海上安全培训课课件
- 神经外科重症管理临床指南
- 少年读史记课件
- 铁路客运防寒过冬课件
- 基础知识产权培训课件
- 2025四川天府新区籍田中心卫生院招聘医师、药师、护士岗位6人笔试参考题库附答案解析
- 2025年三力测试题试题及答案
评论
0/150
提交评论