memcpy()函数的特性和功能

函数原型:void* memcpy(void* dst,const void* src,size_t size);
函数作用:将src所指的内存单元拷贝到dst所指的内存单元,一共拷贝size个字节。如果src和dst存在重叠区域,其行为是未定义的。但是可以肯定的是,无法完整的把src的内存区域拷贝到dst,dst区域中将会存在重复的元素
注:所谓的重叠是指dst指向src内存区域中的某个单元,或者src指向dst中的某个单元

例:int src[10];int* dst=src+5; 或者 int dst[10];int* src=dst+5;
则称src和dst之间则存在重叠区域

所以,如果自己编写一个memcpy()函数,且保证要能完整的将源区域元素拷贝到目标区域。则需要处理发生重叠区域的特殊情况。因此,新memcpy()函数需要实现两个功能。第一,无重叠区域,直接拷贝;第二,存在重叠区域,进行相应的处理。

接下来要思考的则是如何判断两者之间是否存在重叠区域呢?
首先,思考一下我们是如何内存拷贝的。内存拷贝既可以从前往后也可以从后往前进行拷贝。
然后观察一下存在内存重叠区域时的情况。可以发现内存重叠时存在两种情况:

  1. dst<=src<dst+size;即src的内存区域在dst区域的后半部分,这种情况直接可以从前往后进行拷贝。
  2. src<=dst<src+size;即dst的内存区域在src区域的后半部分,这种情况则需从后往前进行拷贝

之后再次简化,可以发现只要dst<=src,直接从前往后拷贝;只要src<dst,则可以直接从后往前拷贝。这样就能完整的将src内存块拷贝到dst中。

为化简的流程

Created with Raphaël 2.2.0 开始 是否重叠 重叠类型 类型一 从前往后拷贝? 结束 类型二 从后往前拷贝 yes no yes no yes yes

化简流程图后可得

参考文档

Created with Raphaël 2.2.0 开始 dst<=src 从前往后 结束 从后往前 yes no

因此可得:

void* memcpy_s(void* dst,const void* src,size_t size){
	if(!src||!dst)
		return 0;
	char* tmp=(char*)dst;
	const char* s=(char*)src;
	
	//存在重叠区域:src<=dst<src+size,从后往前拷贝
	if(s<=dst&&dst<s+size){
		while(size--){
			*(tmp+size)=*(s+size);
		}
	}
	//其它所有情况直接从前往后
	else{
		while(size--)
		*tmp++=*s++;
	}
	return dst;
}

Linux上的memmove()
void *memmove(void *dest, const void *src, size_t count)
{
	char *tmp;
	const char *s;
	//只要目的地的起始地址小于源地址,从前往后
	if (dest <= src) {
		tmp = dest;
		s = src;
		while (count--)
			*tmp++ = *s++;
	} else {
		tmp = dest;
		tmp += count;
		s = src;
		s += count;
		while (count--)
			*--tmp = *--s;
	}
	return dest;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值