栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

C语言——指针与地址的关系

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C语言——指针与地址的关系

文章目录
  • 1、通过指针详细解释数据在内存中是如何存储的
  • 2、指针与地址的区别

1、通过指针详细解释数据在内存中是如何存储的
#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)所示:根据下图及下面的程序输出结果结合便能理解


  • 结论二
    四字节数据在地址中存储方式为小端模式,即低字节存储在低地址中。
2、指针与地址的区别

指针与地址最大的区别就是,指针可以自增,地址不能自增;可以对指针进行取值,若想对地址(这里指立即数,例0x45FE)进行取值,则必须把地址强转为指针类型再进行取值

  1. 不同类型指针指向同一变量,然后对指针取值(下面代码编译会出警告,原因上面已解释)
#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;等等。

  1. 将地址强转为指针类型,对其赋新值
#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;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/988196.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号