对C指针的深入理解

指针是一片内存开始的地址,但是定义指针的时候却往往要加上类型。

例如:int *p;

而且指针指向的数据的类型和声明还要匹配(C标准不匹配可以编译通过且可以运行;C++标准不匹配编译报错)。

于是就激发了我研究为何要这样规定的兴趣。经过研究和实验,发现了原因,并且也加深了对指针的理解!!!

下面一一道来。


先上结论:声明指针所指向的数据的类型,其实就是告诉计算机一次读多少字节以及如何解析这些数据。

例如:char *p,当你调用*p的时候,计算机会去找p所存的地址,由于声明的是char,所以只会读取一个字节,并且按照char进行解析数据;

例如:int *p,当你调用*p的时候,计算机会去找p所存的地址,由于声明的是int,所以依次往下读取四个字节,并且按照int进行解析数据;

例如:float *p,当你调用*p的时候,计算机会去找p所存的地址,由于声明的是float,所以依次往下读取四个字节,并且按照float对数据解析;(注意:虽然int和float都是4字节,但由于对数据的解析形式不同,因此不能混用)

例如:double *p,当你调用*p的时候,计算机会去找p所存的地址,由于声明的是double,所以依次往下读取八个字节,并且按照double对数据解析;

。。。。。。以此类推~~~


结论看着好像很简单,其实里面有很多耐人寻味、值得挖掘的东西!!!细看下文。


以下实验均在win8-64位系统下虚拟机中的XP系统中进行,IDE为VS2010版。


这个我们可以看到,char/int/double分别占1/4/8个字节,而指针,无论指向什么类型,都是占4个字节。


【char】


看上面代码以及运行情况!

(注意代码的第7行,没有写成char **pp=&p,故意写成char *pp=&p!要想编译通过,需要把文件后缀名改为.c



     ch  chx     ppp


他们的内存图如下图所示


ch和chx都是占1个字节,存放A和B,p中此时存放ch的地址,pp中此时存放p的地址


然后把代码中的注释打开,继续运行,得到下图结果




代码乍一看是错的,但是结果以及内存分析来看,似乎又是正确的。~~~


再看一张图


按%x打印*pp,此时没有打印0x0012ff57,而仅仅打印了57,这点对下面的分析很重要。!

原因分析:在执行赋值语句*pp=&chx时,由于*pp是指向char类型,所以在执行*pp时只会读取一个字节(这点很重要),*pp的值为0x0012ff63,所以只读取到了63而已,剩下的0012ff没有读到。而等式右边&chx=0x0012ff57,用这个值给*pp也就是63赋值,会丢掉0x0012ff,仅仅把57赋值给63。此时指针p中存储的值恰好就是0x0012ff63。此时p恰好可以正确指向chx,因此出现了正确的结果。很显然,这是一种巧合(因为chx的地址为0x0012ff57,p的值一开始为0x12ff63,两者只有最低位的一个字节不一样而已!)。

这一组拿的char做测试,下面咱拿int试试看!分析同理。


【int】

这次图一起上



db1db2 p pp



结果也是正确的!

分析同char。这次指针指向一个int型,int型占4个字节,刚好跟地址所占的字节数相同,所以此时结果正确是一定的,而没有那么巧合(char类型时经过分析,只有当地址的最低位不同时才会出现正确结果,而int则没有这个问题)。


【double】

下面再来看double型




此时报错啦!

为什么呢?请转到本文一开始黑体字部分:

【“例如:double *p,当你调用*p的时候,计算机会去找p所存的地址,由于声明的是double,所以依次往下读取八个字节,并且按照double对数据解析;”】

出错就出错在这一句:*pp=&db2;

pp指向double型,8个字节;&db2是一个地址,4个字节。当你写出*pp时,会去找pp所存地址的内存单元,然后往下读取8个字节。而此时&db2只有4个字节。我本来要读8个,你只给我了4个,当然报错啦!(char的时候是,我要读1个,你给我了4个,那我就读最低位那个好了)。



最后上一个比较有意思的实验




这个实验也印证了前面的分析!


【写在最后】指针博大精深,今天领教到了!!!

发布了23 篇原创文章 · 获赞 63 · 访问量 10万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章