const指针(转载+整理)


深入理解const char*p,char const*p,char *const p,constchar **p,char const**p,char *const*p,char**const 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,因此charconst*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或者charconst *p(因没有const*p运算,因此const是前面的char):可以任意位置(非系敏感区域)操作。是相char *p所限定的内容)
(3)char *const p
const 的是p):只能某个固定的位置写操作,并且在p就必初始化(因在后面不能“p=..”的操作,因此就不能在后面初始化,因此只能在定义时初始化)。(某个固定的位置是相char *p所限定的内容)
可以总结以上3char *p中的指p通常是万能的工作指,而(2)和(3)只是在(1)的基上加了些特定的限制些限制在程序中并不是必的,只是了防止程序的粗心大意而生事与愿错误
另外,要明白内存空都可有名字;每内存空内容皆可(除非有所限)。比如函数里定char s[]="hello";上在程的内存里开辟了6量共6个字的空,其中6个字符量的名字分别为s1[0]s1[1] s1[2]s1[3]s1[4]s1[5](内容是'\0'

{

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

}

(4)上面的(2)(3)只是p行限定,没有也不能p所指向的空间进行限定,"char s[]="hello";constchar*p=s;" 然不能通*(p+i)='x'或者p[i]='x'来修改数元素s[0]s[4],但可以通*(s+i)='x'或者s[i]='x'来修改原数元素的--RAM里内存元的可可写属性不因工作指的限定而改,而只会因其本身的限定而改。如const char c‘A’,cRAM里一个内存元(8)的名字,内存元的内容只可,不可写。

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

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

(7)char **const p :涉及两个指p *pconstpp行上面情况(3)的限定,而*p,没有任何限定。

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

1问题

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

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

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

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

2。判断规则

明确const象!于指p1,和p2,若要使得p2=p1成立,

char *p1;char const*p2=p1;//合法:p1是指向(char型的指p2是指向const限定"(char)型的指

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

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

char**p1;char*const*p2=p1;//合法: p1是指向(char *型的指p2是指向const限定"(char*)型的指

五、其他

1。含有const单层或双法:

“p是一个指,是一个[const限定的]指向[const限定的]X型的指

例如:constchar* const *p就是p是一个const限定的指向const限定的(char*型的指

2。定义时const象是确定的,但不能在定义时加括号,不然就和定义时()表示的函数型相混淆了!因此定义时不能写(char *)const *p或者(constchar) **p

六、问题(由于博文后的留言有字符数目限制,将回复移到里)

问题1 博文后留言):解非常好,不有个问题想探下:例如: const char wang[]={"wang"}; char *p; p=wang; 错误的。所以char *p中的P不能指向常量。1)需要正。

回复:你好!谢谢指正!我在ubuntu 10.04gcc 4.4.3)下做了如下测试
//test_const.c
#include<stdio.h>
int main()
{
const char wang[]={"wang"};
char *p;
p=wang;
p[2]='c';
printf("p is %s\n",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 targettype
行:

./test_const
p is wacg
结论根据本博文中第四点--相容性问题,将const型的wang赋值给p是不合法的。编译其的理只是警告,因此p修改了只区域的数据。这应该该编译理不所致后果,不知你用的什么编译器?

问题2 回答http://www.linuxsir.org/bbs/showthread.php?t=239058提到的问题

c言里

// test.c
int main() {
const char* s1 = "test";
char *s2 = s1;
s2 = "It's modified!";
printf("%s\n",s1);
}
out: It's modified!;
这样也可以? 照我的理解不是const限定符在c言里只是摆设一个?

回复:

(1)首先,以上代码编译时会出warning: initialization discards qualifiersfrom 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 = "It's modified!"; //
在只数据区开辟15"It's modified!",并将s2由指向't'而指向"It's modified!"的首字符'I'
printf("%s\n",s1); //
s1所指的‘t’开始出字符串"test"
}


(3)
总结:提者的区在于,s2 = "It's modified!"“test”所在区域的重新赋值,其实这里只是将万能工作指s2指向另外一个新开辟的区域而已。比如若在char *s2 = s1后再s2[2]='a'“test”的区域行了写操作,会出错误个段错误const没有关系,因“test”这块区域本身就是只的。了防止理解出,凡事赋值(比如 s2 = "It's modified!" ),将其做:将s2指向“ It's modified! ”所在区域的首字符。


(4)外收gcc -o test test.c后,“test”“It's modified!”"%s\n"都被作字符串常量存在二制文件test的只

(.rodata)。事上,一个程序从编译到运行,对变量空分配的情况如下:

A赋值了的全局量或static=>放在可行文件的.data段。

B。未赋值的全局量或static量=>放在可行文件的.bss段。

C。代中出的字符串常量或加了constA>放在可行文件的.rodata段。

D一般的局部量=>在可行文件中不占空,在制文件作为进程在内存中运行它分配

E。代mallocnew出的量=>在可行文件中不占空,在制文件作为进程在内存中运行它分配堆空

问题3:(待一步分析)验证博文中三(3)提到的是否s分配空,初步分析:不分配!文中的s只是s0]的地址的代号而已。

#include<stdio.h>
int main() {
int a=3;
char s1[] = "test";
int b=4;
char s2[] ="test2";
printf("the address of a is %u\n",&a);
printf("s1 is %u\n",s1);
printf("the address of s1 is %u\n",&s1);
printf("the address of b is %u\n",&b);
printf("s2 is %u\n",s2);
printf("the address of s2 is %u\n",&s2);
}

果:


the address of a is 3213037836
s1 is 3213037827
the address of s1 is 3213037827
the address of b is 3213037832
s2 is 3213037821
the address of s2 is 3213037821


果可以看出,编译器做了些化。

七、其他相关典文章转载


王海宁,远见嵌入式学院讲师const字的理解

http://www.embedu.org/Column/Column311.htm


目前在C补习时发现很多的同学const个关字的理解存在很大的解。总结对这个关字理解上的区,希望在以后的程中,能灵活使用const个关字。

1 const量是常量

问题,很多同学认为const量是不能改果就误认为该变成了常量。那么const如何理解那?

下面我来看一个例子:

int main
{
char buf[4];
const int a = 0;

a = 10;
}

个比容易理解,编译器直接报错,原因在于“a = 10const量,后面赋值操作。好像明了const量是不能被修改的,那究竟是不是那,那么下面我个例子修改下:

int main
{
char buf[4];
const int a = 0;

buf[4] = 97;//溢出改变下一个字节的地址
printf(“the a is %d\n”,a);
}
//VS2005 win7 X64下验证发现结果是0const常量没有被修改

其中最后一句printf的目的是看下a是否改,根据const的理解,如果const的是量是不能被修改的,那么a一定不会改,肯定0。但是在实际运行的果中,我们发现a经变为97了。这说consta,已被我程序修改了

两个例子,我来分析下,于第二例子,修改的原因是buf[4]赋值操作,我知道buf[4]量已造成了buf个数组变量的越界访问buf的成本身只有0,1,2,3,那么buf[4]访问的是那,根据局部量的地址分配,可以知道buf[4]的地址和int a的地址是一,那么buf[4]实际上就是访问const int a;那么buf[4]的修改,自然也修改了const int a的空也是什么我在最后打印a候看到了97果。

那么我们现在可以知道了,const量是不具不允修改的特性的,那么于第一个例子的象我又如何解那。

第一个例子,错误是在程序编译出的,注意里,候并没有生成可行文件,const量可否修改是由编译器来帮我了。而第二个例子里,量的修改是在可行程序行的候修改的,a是一个量。

上所述,我可以得出一个结论,那就是const量,其实质是告程序编译该变,如果程序在程序中示的修改一个只读变量,编译器会毫不留情的出一个error。而于由于像数溢出,式修改等程序不写造成的运行程中的修改,编译器是无能力的,也const量仍然是具备变量属性的。

2、被const量,会被操作系,防止修改

如果于第一个问题,有了理解的,那么问题,就非常容易知道答案了。Const量是不会被操作系的。

其原因是操作系常量,而不会保护变量的写。那么什么是常量?比如“hello world”个字符串就是被称字符串常量。

问题的另一种明方法,可以看下面个程序:

int main
{
const int a;
char *buf = “hello world”;

printf(“the &a is %p, the buf is%p\n”,&a, buf);
}

可以发现buf保存的地址是在0x08048000个地址附近的,而a的地址是在0xbf000000个地址附近的,而0x08048000附近的地址在我linux操作系上是代段。明了常量和量是存放在不同区域的,自然操作系是会保常量的。

如果我知道个道理后,再看下面的目:

int main
{
char *buf = “hello”;

buf[0] = ‘a’;
printf(“the buf is %s\n”,buf);
}

可以思考下,个程序的运行果会是什么呢?

答案:报错error:在0x08048000处不可以写。也就是说OS保护常量的区域,只能读不能写。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值