0801内存操作函数及其相关

内存操作相关函数

这类函数主要在内存中修改数据。

memcpy

存在于string函数库中,其源码如下所示

  void * __cdecl memcpy(void * __restrict__ _Dst,const void * __restrict__ _Src,size_t _Size)

 其主要的功能和作用是:用src区里的数据覆写dst区的数据。

其主要工作方式如下

	//功能 
	//形参1:目的地址
	//形参2:来源地址
	//形参3:需要拷贝的字节数量,特别需要注意考虑内容的类型,进行必要的计算(总空间=数据类型空间占有量*元素数)
	memcpy(b,a,8);

 数组之间的拷贝

{
	int a[5]={-10,-20,30,40,50};	//int类型,一个元素是4个字节 
	
    //	00 00 00 00 一个字节最大值FF
    //  我们这种是小端模式 
    //  10 00 00 00  还是 00 00 00 10 根据编译器及系统决定是小端模式,还是大端模式
	print(a,5);
	printf("a数组的首地:%#p\n",a);
	char *p=&a;
	printf("a数组的首地:%#p\n",p);
	int i;
	for(i=0;i<8;i++)
	{
		printf("p内容%#p    ",(p+i));
		printf("*p内容%x\n",*(p+i));
	}
		
	int b[5]={0};
	memcpy(b,a,8); 
	
	print(b,5);
}

 输出为

 其中,单个整型元素的大小为4byte,程序中size为8byte,所以从b[0]有2个整形元素被覆写。

*使用memcpy函数时,特别要注意数据长度。如果复制的数据类型是char,那么数据长度就等于元素的个数。而如果数据类型是其他(如int, double, 自定义结构体等),就要特别注意数据长度的值。
建议使用 n * sizeof(type_name)的写法。

重叠拷贝(数组元素在数组内部拷贝)

若输入的size不足以被数据类型占有空间整除会发生什么?

 明明pa[2]只保留了前2个字节,却还是覆写了b[2]。

这里又会涉及到big-endian和little-endian的问题。假设是小端方式储存(更常见),那么读到的是元素1的低8位,写成十六进制即0x1。

由于指针加减常数,单位是与类型保持一致的,也就是在a的基础上,增加3倍int长度,对应的是元素3的地址。b2被替换为0。元素4写成十六进制是0x0004,低8位被替换为0x1,变为0x0001。

因此b2会被覆写。

数组内部拷贝

{
	int a_04[10]={-1,-2,-3,-4,-5,-6,-7,-8,-9,-10};
	print(a_04,10);
	//拷贝元素0 、1 到元素 8 、9的位置
	//结果:int a_04[10]={-1,-2,3,4,5,6,7,-1,-2} 
	//memcpy(&a_04[8],&a_04[0],4);
	//利用memcpy函数,实现同一数组内,内容的拷贝,不交叉 
//	memcpy(a_04+8,a_04,8);
//	print(a_04,10);
	//拷贝元素0 、1 、2到元素 1 、2 、3的位置   往后拷贝 
	//结果:int a_04[10]={-1,-1,-2,-3,-5,-6,-7,-8,-9,-10} 
	//*****memcpy在其他平台上,可能存在只能从前向后拷贝***** 
//	memcpy(a_04+1,a_04,12);
//	print(a_04,10);
	
	//拷贝元素0 、1 、2到元素 1 、2 、3的位置   往前拷贝 
	//结果:int a_04[10]={-3,-4,-5,-4,-5,-6,-7,-8,-9,-10} 
//	memcpy(a_04,a_04+2,12);
//	print(a_04,10);
	
	//利用memcpy函数,实现同一数组内,内容的拷贝,不交叉 
//	memmove(a_04+8,a_04,8);
//	print(a_04,10);
	
	//拷贝元素0 、1 、2到元素 1 、2 、3的位置   往后拷贝 
	//结果:int a_04[10]={-1,-1,-2,-3,-5,-6,-7,-8,-9,-10} 
//	memmove(a_04+1,a_04,12);
//	print(a_04,10);
	
	//拷贝元素0 、1 、2到元素 1 、2 、3的位置   往前拷贝 
	//结果:int a_04[10]={-3,-4,-5,-4,-5,-6,-7,-8,-9,-10} 
	memmove(a_04,a_04+2,12);
	print(a_04,10);
	
}

 memmove元素后移前移

相较于 strcpy函数 不会具有同样的局限性,但是 memcpy函数也是有其的巨大缺陷,其不能对本身进行覆盖拷贝,于是便有了 memmove函数 ,其是能够对本身进行覆盖拷贝的函数,其又同时兼备了 memcpy函数 可做的事。

memmove定义如下

memmove(a_04+8,a_04,8);    //与memcpy相似,都是目的-起源-字节数的格式
void test04(void)
{
	int a_04[10]={-1,-2,-3,-4,-5,-6,-7,-8,-9,-10};
	print(a_04,10);
	memmove(a_04,a_04+2,12);
	print(a_04,10);
	
}

  

memset

memset是一个初始化函数,作用是将某一块内存中的全部设置为指定的值。

其源代码如下图所示:

  void * __cdecl memset(void *_Dst,int _Val,size_t _Size);

dst为目的地址

val为要填充的值(但填充的值大小有限:memset函数是按照字节对内存块进行初始化,所以不能用它将int数组出初始化为0和-1之外的其他值(除非该值高字节和低字节相同)。
其实c的实际范围应该在0~255,因为memset函数只能取c的后八位给所输入范围的每个字节。也就是说无论c多大只有后八位二进制是有效的。一旦超过这个范围数据就失去控制。)

size为数据占有的空间

{
	char a_05[5]={0};
	memset(a_05,'c',4);
	print_c(a_05,5);
	//数据存储 
	int a_25[5]={0};
	memset(a_25,4626,4);    //测试若填充数爆表后会发生什么
	print(a_25,5);
	
}

 打印结果(其中上半部分为a05的填充,下半部分为a25的填充)

其中从a25[0]的填充数与4xxx差距明显,表明该指令对填充数大小有限制

memcmp

这项指令旨在比较两个同类型数组前数个存储单元内数据的大小,该数组按字节大小比较。

指令源代码格式如下

int __cdecl memcmp(const void *_Buf1,const void *_Buf2,size_t _Size);
memcmp(a_06,b_16,7);

其中buf1 buf2为参与比较的两个数组,size为数据占有的空间大小

当buf1<buf2时,返回值<0

当buf1=buf2时,返回值=0

当buf1>buf2时,返回值>0

例:

{
	int a_06[]={10,1315602,13,14,15};
	int b_16[]={10,1381138,22,23,24};
	//a_06[0] 10  00 00  00
	//a_06[1] 12  13 14  00
	
	//b_16[0] 10  00 00  00
	//b_16[1] 12  13 15  00
	
	int ret=10;
	ret=memcmp(a_06,b_16,7);
	printf("ret = %d\n",ret);
}

如何比较大小?

对于整型和浮点型数组,只需比较数组内各元素大小即可。对于字符串,先把元素转换为ascⅡ的整数再逆序比较。

sizeof(测量)的易错点

(&a[0]+1)    以二维数组a的第0行地址为起点下移一行,即行1的头地址
(a[0]+1)     在a[0]行内,从a[0][0]开始取行内下一个元素的地址。
(a+1)        取地址,从行0开始指向下一行
*a+1         指向下一行
*a           取元素a[0][0]的内容

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值