memmove 和 memcpy的区别以及处理内存重叠问题
2016年05月15日 19:30:16 Li_Ning_ 阅读数:17777 标签: memmovememcpy内存重叠 更多
个人分类: C
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Li_Ning_/article/details/51418400
区别:
memcpy和memmove()都是C语言中的库函数,在头文件string.h中,作用是拷贝一定长度的内存的内容,原型分别如下:
-
void *memcpy(void *dst, const void *src, size_t count);
-
void *memmove(void *dst, const void *src, size_t count);
他们的作用是一样的,唯一的区别是,当内存发生局部重叠的时候,memmove保证拷贝的结果是正确的,memcpy不保证拷贝的结果的正确。
一、memcpy函数
Memcpy原型:
void *memcpy(void *dest, const void *src, size_t n);
描述:
memcpy()函数从src内存中拷贝n个字节到dest内存区域,但是源和目的的内存区域不能重叠。
返回值:
memcpy()函数返回指向dest的指针。
二、memmove函数
memmovey原型:
void *memmove(void *dest, const void *src, size_t n);
描述:
memmove() 函数从src内存中拷贝n个字节到dest内存区域,但是源和目的的内存可以重叠。
返回值:
memmove函数返回一个指向dest的指针。
从上面的描述中可以看出两者的唯一区别就是在对待重叠区域的时候,memmove可以正确的完成对应的拷贝,而memcpy不能。
内存覆盖的情形有以下两种,
先看memcpy()和memmove()这两个函数的实现:
-
void* my_memcpy(void* dst, const void* src, size_t n)
-
{
-
char *tmp = (char*)dst;
-
char *s_src = (char*)src;
-
while(n--) {
-
*tmp++ = *s_src++;
-
}
-
return dst;
-
}
从实现中可以看出memcpy()是从内存左侧一个字节一个字节地将src中的内容拷贝到dest的内存中,这种实现方式导致了有地址覆盖的可能,对于图中第一种内存重叠情形(src<dst+count)下,就有((dst+count)-src)个空间地址单元被覆盖,对于上面的图中第一种情况:就有目标字符串dst的最后((dst+count)-src)=((0+5)-3)=2个单元重叠,也就是最后两个字节的拷贝值(4、5)明显不是原先的值(1、2)了,原来的值(1、2)被新的值(4、5)覆盖了,新的值是变成了src的最开始的2个字节(4、5)了。把源字符串src中最前面2个的值更改了,这是程序员不想要的结果。
对于图中第二种内存重叠情形(dst<src+count)下,就有((src+count)-dst)个空间地址单元被覆盖,对于上面的图中第二种情况:就有目标字符串src的最后((src+count)-dst)=((0+5)-3)=2个单元重叠,也就是最后两个字节的拷贝值(1、2)明显不是原先的值(4、5)了,原来的值(4、5)被新的值(1、2)覆盖了,新的值是变成了dst的最开始的2个字节(1、2)了。把源字符串src中最后的2个的值更改了,这是程序员不想要的结果。
而对于第一种内存覆盖情况,memcpy的这种拷贝方式是可以的。???
而memmove就是针对第二种内存覆盖情形,对memcpy进行了改进,改进代码如下:
-
void* my_memmove(void* dst, const void* src, size_t n)
-
{
-
char* s_dst;
-
char* s_src;
-
s_dst = (char*)dst;
-
s_src = (char*)src;
-
if(s_dst>s_src && (s_src+n>s_dst)) { //-------------------------第二种内存覆盖的情形。
-
s_dst = s_dst+n-1;//将目标地址指针移动到n-1的位置
-
s_src = s_src+n-1;//将源地址指针移动到n-1的位置
-
while(n--) {
-
*s_dst-- = *s_src--;//从高地址开始向低地址逐个复制,这样就不会把原地址的内容更改掉了。
-
}
-
}else {//当s_dst<s_src的情况时,说明源字符串地址没有覆盖目标字符串的地址,但是有源字符串覆盖
-
//源字符串的情况,这种情况是运行的。所以可以从低地址向高地址进行逐个复制
-
while(n--) {
-
*s_dst++ = *s_src++;
-
}
-
}
-
return dst;
-
}
在第二种内存覆盖的情形下面,memcpy会出错,但是memmove是能正常工作的。
赐教!