memcpy与memmove函数的区别和实现

1.函数定义

memcpy与memmove都是C语言的库函数,在头文件string.h中,作用是内存拷贝。唯一的区别是,当内存发生局部重叠时,memmove保证了拷贝的结果是正确的,但是memcopy不一定是正确的。但是memcpy比memmove速度快。

void * memcpy ( void * destination, const void * source, size_t num );
void * memmove ( void * destination, const void * source, size_t num );

destination即目标空间,即要复制到哪个空间
source即源空间,即要被复制的内存空间
num即要复制多少个字节的内容到destination
void*即返回目标空间

 这是对memcpy和memmove函数的声明,可以明确看出,其返回的是void*类型的指针,并且有三个参数,第一个参数表示目标地址,第二个参数表示源地址,第三个参数表示拷贝大小(单位是字节)。此函数代表着,在内存空间中,从source指向的空间开始,往后一共num个字节的内存空间,将这些空间里面的内容拷贝到 从destination指向的空间开始,往后一共num个字节的内存空间。
 

2.memcpy代码实现

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

3.memmove代码实现

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

4.内存拷贝原则

首先将void*强制转换成char*;其次一个字节一个字节拷贝内存;然后指向目标空间和源空间地址的指针每次往后走一个字节的位置,循环拷贝相应的字节数即可。

5.拷贝情况分类

1)两块不同的内存,memcpy和memmove拷贝结果一致。

2)内存重叠,分为两种情况。如下图所示:

 代码验证三种情况如下:

#include <stdio.h>
#include <string.h>
int main()
{
	char szdes[40];
	char szsrc[] = "Pierre de Fermat";

	memcpy(szdes, szsrc, strlen(szsrc) + 1);//+1是因为要拷贝\0
	printf("%s\n",szdes);

	int arr1[10] = {0};
	int arr2[5] = {4,2,55,88,3};
	memcpy(arr1+3, arr2, sizeof(arr2));  //arr1是 arr1[10]这个数组首元素的地址,+3就是跳过3个int类型的数据
	for (int i = 0;i < 10;i++)
		printf("%d, ", arr1[i]);
	printf("\n");

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

	int arr4[10] = {1,2,3,4,5,6,7,8,9,10};
	memmove(arr4, arr4+2, 5*sizeof(int));
	for (int i = 0;i < 10;i++)
		printf("%d, ", arr4[i]);
	printf("\n");

	int arr5[10] = {1,2,3,4,5,6,7,8,9,10};
	memcpy(arr5+2, arr5, 5*sizeof(int));
	for (int i = 0;i < 10;i++)
		printf("%d, ", arr5[i]);
	printf("\n");

	int arr6[10] = {1,2,3,4,5,6,7,8,9,10};
	memmove(arr6+2, arr6, 5*sizeof(int));
	for (int i = 0;i < 10;i++)
		printf("%d, ", arr6[i]);
	printf("\n");

	return 0;
}

window上vs输出结果为:

 linux 输出结果为:

6.总结

1)szsrc拷贝到szdes 上(arr2拷贝到arr1上),由于两块不同的内存块,memcpy和memmove功能一样,拷贝正确。

2)arr3和arr4,由于dest的指针地址在src的地址前面,且拷贝是一个字节一个字节的拷贝,虽然有局部内存重叠,但是按照从前往后拷贝的原则,其覆盖内容是旧空间的内容,memcpy和mommove的拷贝都是正确的。

3)arr5和arr6,由于dest的指针地址在src的地址后面,这种情况下,memcpy拷贝可能会存在错误,memmove拷贝正确。如上两图的输出结果可以看出,相同代码在不同环境下,其数据的内容不一致。此种拷贝linux的运行结果错误。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值