对memcpy函数和memmove函数的理解和实现

  两个函数都是将某一内存区域中的指定内容拷贝到目标内存中去,因此,拷贝的类型便不再受限制,不仅可以拷贝字符串内容,也可以拷贝整形,浮点数……

首先看看memcpy函数的用法:

void *memcpy( void *dest, const void *src, size_t count );
返回类型是void *;
参数 dest,src的类型都是void *(可以接收任何类型参数的地址,不限制传入参数的类型)
参数count是拷贝的字节数,类型是size_t无符号整型

实现起来也很简单,如下所示:

int main()
{
	 int arr1[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
	 int arr2[10] = {0};
	 int i = 0;
	 memcpy(arr2,arr1,40);
	 for(i=0; i<10; i++)
	 {
 		 printf("%d ", arr2[i]);
	 }
	 return 0;
}

下面我们写一个函数my_memcpy来模拟实现该函数

void* my_memcpy(void* dest, const void* src, size_t count)
{
	 void * ret = dest;
	 assert(dest && src);
	 while (count--)
	 {
		 *(char*)dest = *(char*)src;
	  	 //不能写成(char*)dest++,因为++的优先级高于(),而dest的类型是void*,不能++或是*
  		 //可以写成dest = (char*)dest+1,因为dest时void*的指针,可以接收任何类型的指针
  		 //也可以写成((char*)dest)++
 	  	 ++(char*)dest;
		 ++(char*)src;
	 }
	 return ret;
}

但是,当拷贝的内容所在内存有重叠时,这个函数就不再适用,结果会是这样:
在这里插入图片描述
什么是内存重叠呢,我画图来解释:
在这里插入图片描述
  红色框和绿色框重叠的部分就是内存重叠的部分。因此,在上面的代码中,内存会从前向后拷贝,2->0,3->1,当4所在内存拷贝时,原内存区域内存放的早已不是2,而是拷贝后的0,导致结果出错。

  当然了,如果你心存疑虑,用库里边的memcpy函数来验证,可能也会得到正确结果,不过这也不能说明我们写的这个my_memcpy函数是错的,因为c语言标准规定了memcpy函数只需要实现拷贝两块不相干的内存块即可,内存重叠的情况交给memmove去实现。我觉得为了严谨,也出于函数被制定出来的最初意义,如果内存重叠了就直接调用memmove函数。

  这是在一个论坛上看到的,我觉得说的很有道理,分享给大家,希望对你们有帮助:在这里插入图片描述

下面我们来看看memmove函数的用法

void *memmove( void *dest, const void *src, size_t count );
返回值和参数和memcpy函数一样,不同点就在于内存重叠部分,我们用memmove来实现一下上面所写的数组的拷贝:

在这里插入图片描述
这次得到了正确结果,下面我们写my_memmove来模拟实现该函数:

void* my_memmove(void* dest, const void* src, size_t count)
{
 void* ret = dest;
 assert(dest && src);
 //分两种情况
 //若目标空间在源空间之前,从前往后移动,若目标空间在源空间之后,从后往前移动
 if (dest < src)
 {
	  //从前往后
	  while (count--)
	  {
		   *((char*)dest) = *(char*)src;
		   ++(char*)dest;
		   ++(char*)src;
	  }
 }
 else
 {
	  //从后往前
	  while (count--)
 	{
	  	 *((char*)dest + count) = *((char*)src + count);
	}
 }
 return ret;
}

对于内存重叠的情况,我们这样处理:当目标空间在源空间之前时,从前向后拷贝;当目标空间在源空间之后,从后向前拷贝:
在这里插入图片描述

void* my_memmove(void* dest, const void* src, size_t count)
{
	 void* ret = dest;
	 assert(dest && src);
	 //分两种情况
	 //若目标空间在源空间之前,从前往后拷贝,若目标空间在源空间之后,从后往前拷贝
	 if (dest < src)
	 {
		  //从前往后
		  while (count--)
		  {
			   *((char*)dest) = *(char*)src;
			   ++(char*)dest;
			   ++(char*)src;
		  }
	 }
	 else
	 {
		  //从后往前
		  while (count--)
		  {
		  	 *((char*)dest + count) = *((char*)src + count);
		  }
	 }
	return ret;
}

这是我对这两个函数的理解,很考察我们对内存,指针的掌握还有一些细节部分的处理。如果有写的不对的地方,敬请指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值