C语言模拟实现memmove的示例代码

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

C语言模拟实现memmove的示例代码

ZHENGZJM   2023-02-03 我要评论

前言

上一篇我们介绍了memcpy和strcpy的区别,以及memcpy模拟实现,但这两个库函数都有一个缺点,那就是不能自己复制自己的内容

例子

这有一个数组arr,其元素分别为1、2、3、4、5、6、7、8、9、10,我们想将1、2、3、4复制到2的后面,从而将数组arr变成1、2、1、2、3、4、7、8、9、10

用memcpy尝试

我们发现,跟我们预期的 1、2、1、2、3、4、7、8、9、10有出入。

错误原因

int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memcpy(arr + 2, arr, 16);

memcpy实现过程

void* my_memcpy(void* dest, void* src, size_t count)
{
    void* ret = dest;
    while (count--)
    {
        *(char*)dest = *(char*)src;
        dest = (char*)dest + 1;
        src = (char*)src + 1;
    }
    return ret;
} 

当我们这样操作时,src一开始指向1,1被复制到了3的位置上,后面指向2,2被复制到4的位置上,当src指针指向原来的3时,指向的内容变成了1,又将1复制到了5的位置上,当src指向原来的4时,指向的内容变成了2,又将2复制到了6的位置上。所以就出错了。

用memmove尝试

我们发现目的达到了,说明memmove适用于内存发生重叠的情况。那么memmove是怎么实现的呢?

memmove的模拟实现

整段代码

void* my_memmove(void* dest, void* src, size_t count)
{
	void* ret = dest;
	if (dest < src)
	{
		while (count--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		while (count--)
		{
			*((char*)dest + count) = *((char*)src + count);
		}
	}
	return ret;
}

memmove的定义

由图可知,memmove的返回值是目标地址,形势参数分别是(目标地址,源头地址,需要操作的字节数)

具体实现步骤

第一种情况(dest在src后),采用由后向前复制

由上面的错误分析,我们知道是因为后面要被复制过去的内容被更改了,还是用上面的例子做示范,我们从1开始复制的话,1会将3覆盖掉,进而导致想将3复制到到5的位置上时,实际上是将1复制到5的位置上。

那么我们如果从4开始复制呢?我们由后至前进行复制,将4复制到6,再将3复制到5,这样我们就不怕3、4被1、2覆盖掉了。

我们要想先将4复制到6,先得将src指向4,dest指向6,然后再进行交换。我们用加传过去的字节数来实现。

*((char*)dest + count) = *((char*)src + count);

我们想将指针前移,直接count减一就行,又因为我们要重复这一行为,所以我们使用while循环来实现。

        while (count--)
		{
			*((char*)dest + count) = *((char*)src + count);
		}

第二种情况(dest在src前),采用由前向后复制

如果dest在src前,我们还能用由后至前的方法复制吗?

例如,我们将3、4、5、6向前移动2次,也就是将1、2、3、4、5、6、7、8、9、10变成3、4、5、6、5、6、7、8、9、10

我们发现并没有成为我们想象当中的样子。

错误原因

依然是要被复制的内容在被复制之前就被更改了,这里先将6移动到4,5移动到3,想将4移动到2时,实际上复制过去的是6,以此类推...

所以我们要采用由前向后复制的方法(【C语言】字符串拷贝函数(strcpy)与内存拷贝函数的不同及内存拷贝函数(memcpy)的模拟实现一文里有)

总结

memcpy不能实现自己拷贝自己,也就是不适用于内存叠加的情况。我们用memmove便可以解决这个问题。

对于memmove的模拟实现,核心思想就是将会被覆盖的、要被复制的内容提前使用。这里分为两种情况,一种是被复制的内容地址在目标内容地址的前面,另一种就是被复制的内容地址在目标内容地址的后面,对于前一种情况,我们使用由后至前进行复制的方法,对于后一种情况,我们使用由前至后进行复制的方法(dest在src后就由后向前。dest在src前,就由前向后)。

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们