- 1、通过指针详细解释数据在内存中是如何存储的
- 2、指针与地址的区别
#include#include int main() { unsigned int a[5]={0x12345678,0x89ABCDEF,0xAF3D1596,0x424AD841,0x5638ECFB}; unsigned int *p = a; unsigned char i; for(i=0; i printf("&a[%d] = 0x%p---->a[%d] = 0x%08Xn",i,&p[i],i,p[i]); } return 0;
可以看出数组a中元素在内存中存储方式是从低地址开始的,如下图方式:
- 结论一
上述虽然可以看出数组中的元素在地址空间中的存储方式,但由于每个数组元素都是unsigned int型,即占四个字节,而每个地址只能放一个字节数据,所以从上述也能看出每个数组元素占用4个地址,那么每个数组元素的四字节数据在连续地址中又是如何存储的呢?下面代码做出解释。
#include#include int main() { unsigned int a[5]={0x12345678,0x89ABCDEF,0xAF3D1596,0x424AD841,0x5638ECFB}; unsigned int *p = a; //这里p是指向数组元素a[0]的首地址,但通过指针取值(或赋值)时,是直接以a[0]首地址为起点,连续取(赋)四个字节。 unsigned char *q = a; //这里定义q为unsigned char*,q也是指向数组元素a[0]的首地址,通过指针取值(赋值)也是只取(赋)首地址的一个字节数据,这里编译会出警告,因为数组a中的元素都是四字节数据,即每个元素占四个地址,这样的话q+1不会跳到下一个数组元素,只会跳到下一个地址(或者说是下一个字节)。 unsigned char i,j; for(i=0; i printf("&a[%d] = 0x%p---->a[%d] = 0x%08Xn",i,&p[i],i,p[i]); } printf("nnn"); for(i=0; i for(j=0; j<4; j++) printf("&a[%d%d] = 0x%p---->a[%d%d] = 0x%Xn",i,j,&q[i*4+j],i,j,q[i*4+j]); printf("n"); } return 0; }
- 解释编译警告,即下面代码引起的警告:因为&a[0]为unsigned int*型,而q为unsigned char *型,赋值号两边指针类型不同,导致警告。
unsigned int a[5]={0x12345678,0x89ABCDEF,0xAF3D1596,0x424AD841,0x5638ECFB};
unsigned int *p = a;
unsigned char *q = a;
指针变量类型一般和所指向的变量类型一致,就是为了取值和赋值时方便
因为数组a中的数据是4字节数据,即每个数组元素都需要4个地址来存储,正常情况下我们也是定义一个4字节指针变量(这样的指针加一是直接跳4个地址,取值和赋值也是连续取(赋)4个地址的值),来指向存放数组元素的地址,如下图(a)所示;但我们如果想知道每个数组元素在内存中是如何存储的,那么这种指针指向就不能展示出来,上面指针q便是指向单字节的指针变量(这样的指针加一,是指向下一个地址,对它取值或者赋值也是只取(赋)一个地址的值,如下图(b)所示:根据下图及下面的程序输出结果结合便能理解
- 结论二
四字节数据在地址中存储方式为小端模式,即低字节存储在低地址中。
指针与地址最大的区别就是,指针可以自增,地址不能自增;可以对指针进行取值,若想对地址(这里指立即数,例0x45FE)进行取值,则必须把地址强转为指针类型再进行取值
- 不同类型指针指向同一变量,然后对指针取值(下面代码编译会出警告,原因上面已解释)
#include#include int main() { unsigned int b = 0x4567ABCD; unsigned int *p = &b; unsigned short int *q = &b; unsigned char *h =&b; int i; printf("&b = 0x%p---->b = 0x%Xn",&b,b); printf("p = 0x%p---->*p = 0x%Xn",p,*p); printf("n"); for(i=0; i<2; i++) { printf("q[%d] = 0x%p---->*q[%d] = 0x%Xn",i,(q+i),i,*(q+i)); } printf("n"); for(i=0; i<4; i++) { printf("h[%d] = 0x%p---->*h[%d] = 0x%Xn",i,(h+i),i,*(h+i)); } return 0; }
这里定义了三个指针变量,全部指向变量b,每个指针变量中存储的都是变量b的地址(系统在内存中,为变量分配存储空间的首个字节单元的地址,称之为变量的地址),这里是0x65FDFC,但由于指针变量p,q,h的类型不同:对指针变量p进行取值或者赋值时,默认以变量b的地址为起始,取或赋连续的4个字节(这里4个字节是因为指针类型为unsigned int*);同理,对指针变量q进行取值或者赋值时,默认以变量b的地址为起始,取或赋连续的2个字节(这里2个字节是因为指针类型为unsigned short int*);对指针变量h进行取值或者赋值时,默认以变量b的地址为起始,取或赋连续的1个字节(这里1个字节是因为指针类型为unsigned char*)。
注:对不同类型指针进行自增运算时,自增一次所跨越的地址数由指针类型决定,如:unsigned int*类型指针变量,自增一次,跨越的地址数为4;同理unsigned short int*类型指针变量,自增一次,跨越的地址数为2;等等。
- 将地址强转为指针类型,对其赋新值
#include#include int main() { unsigned int b = 0x4567ABCD; int i; printf("&b = 0x%p---->b = 0x%Xn",&b,b); printf("&b = 0x%p---->b = 0x%Xn",(unsigned int *)(0x65FE18),*((unsigned int *)(0x65FE18))); printf("n"); *((unsigned char*)(0x65FE18)) = 0xEF; *((unsigned char*)(0x65FE18)+1) = 0x59;//指针加1,地址加1 *((unsigned char*)(0x65FE18)+2) = 0xA8; *((unsigned char*)(0x65FE18)+3) = 0x7B; for(i=0;i<4;i++) { printf("&b[%d] = 0x%p---->b[%d] = 0x%Xn",i,(unsigned char*)(0x65FE18)+i,i,*((unsigned char*)(0x65FE18)+i)); } printf("n"); *((unsigned short int*)(0x65FE18)) = 0x254A; *((unsigned short int*)(0x65FE18)+1) = 0x4C94;//指针加1,地址加2 for(i=0;i<2;i++) { printf("&b[%d] = 0x%p---->b[%d] = 0x%Xn",i,(unsigned short int*)(0x65FE18)+i,i,*((unsigned short int*)(0x65FE18)+i)); } printf("n"); *((unsigned int*)(0x65FE18)) = 0xAEF0127D; printf("&b = 0x%p---->b = 0x%Xn",(unsigned int*)(0x65FE18),*((unsigned int*)(0x65FE18))); printf("n"); printf("&b = 0x%p---->b = 0x%Xn",&b,b); return 0; }



