memcpy、memmove的模拟实现

一.memcpy

声明

void *memcpy(void *str1, const void *str2, size_t n)

作用

将自str2往后的n个字节的数据,复制到str1往后的n个字节的内存当中

模拟实现

void* my_memcpy(void* str1, const void* str2, int n)
{
	while (n--)
	{
		*(char*)str1 = *(char*)str2;
		str1 = (char*)str1 + 1;
		str2 = (char*)str2 + 1;
	}
}

注意

在使用过程中,str1与str2中的n个字节不能重叠。这也是memcpy很大的一个缺陷,而memmove可以很好的解决整个问题

二.memmove

在使用memcpy时,当str1与str2发生重叠时,无法需拷贝的数据可能被覆盖掉,导致无法达到所需的效果

举一个例子来解释

void* my_memmove(void* str1, const void* str2, size_t n)
{
	void* ret = str1;
	while (n--)
	{
		*(char*)str1 = *(char*)str2;
		str1 = (char*)str1 + 1;
		str2 = (char*)str2 + 1;
	}
	return ret;
}
int main()
{
	int arr[] = {1,2,3,4,5,6,7,8,9,10};
	my_memmove(arr+2, arr, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
		printf("%d ", arr[i]);
	return 0;
}

想要达到的效果是,将arr1为起始的20个字节的数据,存放到arr1+2后的20个字节的内存中。

原数组12345678910
目的数组12123458910
实际数组12121218910

这为什么呢?

一.memcpy

声明

void *memcpy(void *str1, const void *str2, size_t n)

作用

将自str2往后的n个字节的数据,复制到str1往后的n个字节的内存当中

模拟实现

void* my_memcpy(void* str1, const void* str2, int n)
{
	while (n--)
	{
		*(char*)str1 = *(char*)str2;
		str1 = (char*)str1 + 1;
		str2 = (char*)str2 + 1;
	}
}

注意

在使用过程中,str1与str2中的n个字节不能重叠。这也是memcpy很大的一个缺陷,而memmove可以很好的解决整个问题

二.memmove

在使用memcpy时,当str1与str2发生重叠时,无法需拷贝的数据可能被覆盖掉,导致无法达到所需的效果

举一个例子来解释

void* my_memmove(void* str1, const void* str2, size_t n)
{
	void* ret = str1;
	while (n--)
	{
		*(char*)str1 = *(char*)str2;
		str1 = (char*)str1 + 1;
		str2 = (char*)str2 + 1;
	}
	return ret;
}
int main()
{
	int arr[] = {1,2,3,4,5,6,7,8,9,10};
	my_memmove(arr+2, arr, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
		printf("%d ", arr[i]);
	return 0;
}

想要达到的效果是,将arr1为起始的20个字节的数据,存放到arr1+2后的20个字节的内存中。

原数组12345678910
目的数组12123458910
实际数组12121218910

这为什么呢?

正在上传…重新上传取消

重叠部分的数据,在拷贝过程中已经被覆盖了,数据已经丢失了

从这里不难发现,memcpy无法处理出现重叠的情况

在这时,我们可以使用memmove

memmove的参数,返回值等等与memcpy均相同,不过他可以处理重叠的情况

正在上传…重新上传取消

正在上传…重新上传取消 对比上下两个例子,不难发现重叠部分是分情况的,

一是与原数据前部分与目标地址重合,另一种是后部分与目标地址重合

想要处理重叠部分,重点便是先使用重叠部分的数据,防止重叠部分的数据被覆盖后,导致的数据丢失

可以通过str1 与 str2 的的地址位置关系来判断

目前的讨论是以重叠为前提的,不重叠时以下要讨论的两种方法都能实现

为了方便讨论,将memcpy中的拷贝方法称作为前拷贝,反之先拷贝高地址处数据的称之为后拷贝

先讨论一个特殊情况 

str1 == str2

 无论是前拷贝还是后拷贝,均无影响。

都是将数据本身赋值给本身

str1 > str2

重叠部分的数据位于源数据的后部分,应优先使用重叠部分

即应使用后拷贝

str1 < str2

重叠部分的数据位于源数据的前部分,应优先使用重叠部分

即应使用后拷贝

总体而言

当str1 < str2时,前拷贝

当str >= str2时,后拷贝

void* my_memmove(void* str1, const void* str2, size_t n)
{
	void* ret = str1;
	if (str1 < str2)
	{
		while (n--)
		{
			*(char*)str1 = *(char*)str2;
			str1 = (char*)str1 + 1;
			str2 = (char*)str2 + 1;
		}
	}
	else
		while(n--)
			*((char*)str1+n) = *((char*)str2+n);
	return ret;
}

C语言中,我们可以模拟实现memcpy函数。memcpy函数的原型为void * memcpy(void * destination, const void * source, size_t num),它的作用是将源地址(source)指向的内存块的数据拷贝到目标地址(destination)指向的内存块中,拷贝的字节数由第三个参数num指定。 要实现memcpy函数,我们可以按照以下步骤进行操作: 1. 首先,我们需要创建一个与源内存块相同大小的目标内存块,并将目标内存块的地址保存在destination指针中。 2. 接下来,我们使用一个循环来逐字节地将源内存块的数据复制到目标内存块中,直到拷贝的字节数达到了num的值。 3. 最后,我们返回目标内存块的地址(destination指针),作为函数的返回值。 下面是一个示例的实现代码: ```c void *my_memcpy(void *destination, const void *source, size_t num) { char *dest = (char *)destination; const char *src = (const char *)source; for (size_t i = 0; i < num; i++) { dest[i = src[i]; } return destination; } ``` 在这个实现中,我们将destination和source指针都转换为char类型的指针,这样可以逐字节地进行数据拷贝。然后,我们使用一个循环来逐字节地将源内存块的数据复制到目标内存块中,直到拷贝的字节数达到了num的值。最后,我们返回目标内存块的地址作为函数的返回值。 这样,我们就实现了一个简单的memcpy函数的模拟实现。需要注意的是,这只是一个简单的示例实现,实际的memcpy函数可能会有更复杂的实现方式,具体实现可能因编译器和操作系统的不同而有所差异。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值