C语言模拟实现memmove函数

C语言模拟实现memmove函数

   有时候我们需要将内存中某一区域的内容拷贝移动到另一块区域,此时可以使用库函数中的memmove函数。那么自己如何实现这个库函数呢?
   首先看一下在cplusplus中该函数是如何定义的。

由在这里插入图片描述
函数参数说明:
void* memmove:void* 表示函数返回值是一个void类型的指针,memmove是库函数的命名(一会自己实现该函数时,需要我们自己把名字修改掉)。
void* destination:目标内存空间的起始地址,void类型的指针。
const void* source:要拷贝移动的源数据所在内存空间的起始地址,void类型的指针,前面的const表示该指针指向的内容不可以被更改。
size_t num:要拷贝移动的字节数,size_t是无符号整形。
接下来以一个例子说明如何实现该函数。
在这里插入图片描述
主函数部分:
在这里插入图片描述
注意:第三个参数是12,不是3。因为arr2是整形数组,一个整形元素占4个字节,所以共拷贝移动34=12个字节。
函数内部:
在这里插入图片描述
注意:
由于函数定义时,前两个参数是void类型的指针,而void型指针无法直接解引用,所以代码①中需要进行(char
)将其转换为字符型指针。特别强调,必须转换为字符型指针,因为字符型指针+1操作后,会指向下一个字节,这样就满足了对内存空间进行拷贝移动的要求。
完整代码如下:

#include<stdio.h>
#include<assert.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
	void* ret = dest;    //记录目标内存的起始位置
	assert(dest && src); //添加断言,防止出现空指针异常
	while (num)
	{
		*(char*)dest = *(char*)src; //将src和dest强转为字符型指针,再复制移动内容。
		 dest = (char*)dest + 1;    //dest指针移动到下一个字节处
		 src = (char*)src + 1;      //src指针移动到下一个字节处
		 num--;
	}
	return ret;
}
int main()
{
	int arr1[20] = { 2,4,6,8,39,50 };
	int arr2[10] = { 1,2,3,4,5,6 };
	my_memmove(arr1, arr2,12);
	for (int i = 0;i < sizeof(arr1) / sizeof(arr1[0]);i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

运行结果如下:
在这里插入图片描述
此时,已经将arr1数组中的前3个元素2,4,6替换成了arr2前三个元素1,2,3。
思考,以上结果实现的前提是,arr2数组和arr1数组指向的内存空间没有重叠的部分,如果有重叠的部分,我们自己实现的函数my_memmove能否满足要求呢?
再来看一个例子。
在这里插入图片描述
此时主函数代码相应变为:

int main()
{
	int arr3[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr3 + 2, arr3,5*4);
	for (int i = 0;i < sizeof(arr3) / sizeof(arr3[0]);i++)
	{
		printf("%d ", arr3[i]);
	}
	return 0;
}

我们期待的结果是:
在这里插入图片描述
实际运行结果是:
在这里插入图片描述
这里运行结果和我们预想的有出入,为什么?
实际上,根本原因是src指向的内存区域与dest指向的内存区域有重叠。接下来用图来演示。
在这里插入图片描述
由于内存重叠,导致在拷贝复制src指向的原始元素时,其中的部分元素被修改,所以出现了我们预期之外的结果,为了解决这一问题,我们可以采取将src指向的内容从后往前进行拷贝移动,具体步骤如图:
在这里插入图片描述
当然,这么做的前提是src指向的内存的地址小于dest指向的内存地址,当src指向的内存的地址大于dest指向的内存地址时,从后往前复制移动依然会出现之前的问题(有兴趣的读者可以仿照上述示意图自己探究下,这里不再赘述)。所以,为了避免出现拷贝复制中出现问题,需要讨论src和dest的位置关系。现在总结如下:
1.若src指向的内存地址小于dest指向的内存地址,从后往前拷贝复制;
2.若src指向的内存地址大于dest指向的内存地址,从前往后拷贝复制。
此时my_memmove函数内部代码如下:

void* my_memmove(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(dest && src);
	if (src < dest)
	{
		//从后往前拷贝
		while (num)
		{
			*((char*)dest+num - 1) = *((char*)src + num - 1);
			num--;
		}
	}
	else
	{
		//从前往后拷贝
		while (num)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
			num--;
		}
	}
	return ret;
}

主函数代码以及两种不同情形下的运行结果如下:
在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值