上一篇介绍了指针数组和数组指针,那么数组就告一段落了,这篇将回归指针。
类型强制转换:
我们知道C语言的基本数据类型之间能够进行强制转换。其实,指针之间也能进行类型强制转换,但是意义并不一样。我们知道指针里保存的是一个地址,不管什么类型的指针存的都是地址,所以再怎么转换地址是不会变得,长度也不会变,贴段代码:
#include <stdio.h>
int main()
{
int a;
int *p1 = &a;
char *p2 = (char *)p1;
printf ("%p\n",p1);
printf ("%p\n",p2);
printf ("%d\n",sizeof(p1));
printf ("%d\n",sizeof(p2));
return 0;
}
打印下结果
怎么样,结果和说的一样吧,那么,这个强行转换究竟干了些啥呢。我们知道int *p
中int的意思吧,就是指针所指地址内数据的类型,有了这些类型,在用*p
取数据的时候才知道该往后取几个字节才能获得自己想要的数。强转干的就是这个事,贴段代码:
int main()
{
int a;
int *p1 = &a;
char *p2 = (char *)p1;
printf ("p1 = %p\n",p1);
printf ("p2 = %p\n",p2);
printf ("p1+1 = %p\n",p1+1);
printf ("p2+1 = %p\n",p2+1);
return 0;
}
打印下结果:
看出什么门道了么,没错,p1,p2向右偏移一位时偏移的字节数不一样,可以看出p1偏移了4个字节相当于一个int的字节数,而p2偏移了1个字节相当于一个char的字节数,这下好理解了,继续看段代码:
int main()
{
int a = 10;
int *p1 = &a;
char *p2 = (char *)p1;
printf ("%d\n",*p1);
printf ("%d\n",*p1);
return 0;
}
打印下结果:
结果一样啊,那我们再看:
int main()
{
int a = 256;
int *p1 = &a;
char *p2 = (char *)p1;
printf ("%d\n",*p1);
printf ("%d\n",*p2);
return 0;
}
打印下结果:
咦,怎么是这样呢,我们从内存来分析下原因。
上图是a = 10
的时候内存里存储情况,注意,我用十六进制数表示了。
上图是a = 256
时候内存里的存储情况,是不错看起来存的很奇怪,注意:我用的机子是小端模式,数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。大部分的CPU都是小端模式,当然通过程序可以测出。
回归正轨,通过两幅图可以看出来了么,相信仔细的分析一下就应该理解了吧,我就不过多的说明了。
这有一题从书上看到的题目,可以加深一下理解:
int main()
{
int a[4] = {1, 2, 3, 4};
int *ptr1 = (int *)(&a + 1);
int *ptr2 = (int *)((int)a + 1);
printf ("%x\t%x\n",ptr1[-1],*ptr2);
return 0;
}
结果是啥呢?
第一个输出的是4相信大家都知道吧,那么这个2000000哪来的呢,我们来看看内存情况。
首先看(int)a + 1
,这里的int已经将a地址转换成整型,这时候它是一个数,而不是地址,加上一然后再由(int *)强转为一个地址,是不是就相当于由a的地址向后移动了一位,然后是指针指向的地址内的数据是整型,所以从当前地址向后取4个字节的内容00 00 00 02,输出的时候经过自动的整理得到02 00 00 00既2000000,注意哦,这里的输出用%x表示输出的是十六进制数,刚好,我在内存里也用十六进制存(当然只是看着是,其实内存里真正存的还是二进制)。