字符函数memmove的使用以及模拟实现

一 . 函数介绍

        前面介绍了对memcpy的使用以及模拟实现 , 明白了memcpy能够对任意数据类型进行指定字节数进行拷贝 .那么 , 当遇到目标空间与源空间在同一数组内,也就是数组自己拷贝自己的情况 , 对于memcpy的模拟实现的代码则无法完成任务 .

        在库函数的标准下 ,memcpy是可以完成数组重叠拷贝 , 而在库函数的规定中memcpy专门用于两个数组之间的拷贝 , memmove则用于数组重叠拷贝 .

        所以,接下来针对memmove进行模拟实现

二 . 分析函数

        2.1参数

首先在cplusplus网站搜索memcpy函数,可以看到对于该函数的定义.他的返回值是void * ,表示函数的返回值是任意类型的指针.

他有三个参数 ,分别对其解释代表的含义.

参数一 (void * dest) :   指向任意类型的指针 , 指向需要存入数据的目标空间.

参数二 (const void * src) : 指向不可修改的空间,指向被拷贝数据的地址.

参数三 (size_t num) : 传入的是需要拷贝的字节个数.

三 . 函数应用

#include<stdio.h>
#include<string.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr, arr + 2, 20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

函数传入的参数表示的目的是 : 将 arr+2 指向的地址往后的20个字节 , 拷贝到 arr 指向的地址 . 

运行结果 : 

成功的将 3 4 5 6 7 拷贝到  1 2 3 4 5 的地址处.

四 . 模拟实现 

        4.1 逻辑梳理

        使用memcpy模拟实现的逻辑 ,是从源空间的第一个字节 , 从前往后的依次拷贝到目标空间中 .所以在memmove的模拟实现中尝试着套用该逻辑

        如图 , 蓝色代表源空间 , 绿色代表目标空间 , 按照从前往后的逻辑 . 将 1 拷贝到 3 的位置 ; 2 拷贝到 4 的位置 ; 将 3 拷贝到 4 的位置 以此类推 . 这是理想的状况 , 可事实并非如此 .仔细思考 ,  当前两个数据拷贝完成后 , 3 和 4 位置的数据就已经发生了变化 , 变成了1212567 , 如果继续拷贝 , 会继续将 1 2 拷贝到 5 和 6的位置, 无法达到预期 , 所以这种逻辑行不通 . 

        那么 ,从前往后不行 , 就尝试从后往前 , 还是以上图为例 ,蓝色代表源空间 ,绿色代表目标空间 ,将 5 拷贝到 7的位置 ; 4 拷贝到 6 的位置 ; 3 拷贝到 5 的位置 ;以此类推 . 不难发现 , 当3 需要拷到5 的位置时 , 5 已经拷贝完成了 , 不会造成未拷贝的数据被覆盖 , 所以这种情况下需要从后往前进行拷贝 .

        但并不是所有情况都适用从后往前 , 比如 , 将上图的源空间和目标空间交换 , 则需要从前往后进行拷贝 . 

        所以,在代码实现的过程中 ,需要对dest 和 src 进行比较 , 是否dest 大于 是src . 若dest大于src ,则需要从前往后拷贝 , 若dest小于src , 则从后往前拷贝 .另外一种情况,两个空间没有重叠的部分,则两种拷贝顺序方式都可以实现 . 

        了解完基本的实现逻辑 , 接下来进行代码的实现 . 

        4.2 代码实现

首先 , 从前往后

        

//前->后
int i = 0;
for (i = 0; i < sz; i++)               //for循环,拷贝sz个字节
{
	*(char*)dest = *(char*)src;        //强转为char*类型,再解引用
    //由于函数适用任意类型的数据,所以拷贝时需要以字节为单位进行拷贝
    
	dest = (char*)dest + 1;            //同理,转为char*,再跳过一个字节   
	src = (char*)src + 1;                
}        

        

 其次 , 从后往前

//后->前
while (sz--)
{
	*((char*)dest + sz) = *((char*)src + sz);
}

这种顺序下 , 是从空间的最后一个字节开始拷贝 , 所以需要找到空间末尾的前一个字节 , 就要先强转为char*类型 , 再加sz个字节 , 由于进入while循环需要判断sz--是否为真 , sz减少一个字节, 所以强转后直接加上sz再解引用,直接拿到最后一个字节的内容 , 再进行拷贝 . 

       这样,两种情况都写完了,最后加上细节部分 , 完整代码 : 

void* my_memmove(void* dest, const void* src, size_t sz)
{
	void* ret = dest;             //创建返回值
	assert(dest&& src);           //断言dest和src不为空指针 

	if (dest < src)
	{
		//前->后
		int i = 0;
		for (i = 0; i < sz; i++)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}

	}
	else 
	{
		//后->前
		while (sz--)
		{
			*((char*)dest + sz) = *((char*)src + sz);
		}
	}

	return ret;                //返回ret
}

        4.3 运行结果

从前往后

从后往前 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值