一、momcpy
momcpy是内存函数中对于指定空间的数据拷贝到另外一个指定的空间中,并根据数据的长度覆盖其中的内容。
说起来memcpy与strcpy有着很相似的地方,那就是功能的实现上:指定拿取源头数据然后覆盖目的地。
不同的是,memcpy是对于内存中的数据进行操作而strcpy是对于字符串进行操作
接下来可以看下它们的实现代码:
char * strcpy ( char * destination, const char * source, size_t num );
void * memcpy ( void * destination, const void * source, size_t num );
可以看到memcpy与strcpy中对于指针的数据类型规范有着很大不同
strcpy指定只能是传入char类型的数据(也就是字符串),memcpy则是void类型。
这就意味着memcpy可以接受任意类型的数据。
注:即使是拷贝数据也是根据字节数来进行操作,1char==1字节;
这里我贴一下实现代码:
void* memcpy(void* dst, const void* src, size_t n)
{
if (NULL == dst || NULL == src)
return NULL;
void* ret = dst;
char *dst_ = (char*)dst;
char *src_ = (char*)src;
while (n--)
{
*dst_++ = *src_++;
}
return ret;
}
二、memmove
memmove与memcpy也很相似,甚至在传参上都一样。
这里我放下函数定义:
void * memmove ( void * destination, const void * source, size_t num );
这里会发现C规定的这两个函数是不是有些矛盾?别急往下看
我找了解释专业的文章贴在上面
可以看出memmove除了具有memcpy的功能甚至多了一个:可以处理重叠空间的数据拷贝。
嗯?怎么回事
发现好像memcpy也能实现mememove的功能?
这里说明一下,主要是每个编译器厂商对于memcpy和memmove都有对应的优化,我使用的VS系列对于memcoy和memmove的功能定义是一致的,
但是对于其他(像是gcc)则是分的很明白,重叠空间的数据拷贝就是由memmove实现。
而且重叠拷贝的也会有一种问题:应该从什么方向开始?
第一种:
将输入区间的元素拷贝到输出区间的红色区点域的位置,也就是输出区间的尾部与输入区间发生重叠,也就是
dst <= src
的情况,这种情况拷贝结果是正确的。
第二种
将输入区间的元素拷贝到输出区间的黑色点区域的位置,也就是输入区间和输出区间完全没有重叠,也就是
(char*)dst >= (char*)src + n
的情况,这种情况拷贝结果是正确的。
第三种:
将输入区间的元素拷贝到输出区间的绿色点区域的位置,也就是输出区间的头部与输入区间发生重叠,也就是
的情况,这种情况拷贝结果会出现问题,因为复制输入区间前,它的元素值可能被覆盖,这种情况memmove函数值这样处理的:反向进行复制,也就是src和dst的尾部成了头部,而头部成了尾部,dst = (char*)dst + n - 1;src = (char*)src + n - 1;然后从右向左复制,就变成第一种情况,这种会保证复制结果是正确的.
dst > src && (char*)dst < (char*)src + n
这里放一下实现代码:
void* memmove(void* dst, const void* src, size_t n)
{
if (NULL == dst || NULL == src)
return NULL;
void* ret = dst;
char *dst_=(char*)dst;
char *src_=(char*)src;
if (dst <= src ||dst_ >= (src_ + n)) //第一种和第二种的情况
{
while (n--) //正向进行复制(从头至尾)
{
*dst_++=*src_++;
}
}
else //第三种情况 反向进行复制(从尾至头)
{
dst_ += n - 1;
src_ += n - 1;
while (n--)
{
*dst_ -- =*src_ --;
}
}
return ret;
}