1.memmove
函数原型:void *memmove(void *dest, const void *source, size_t count)
返回值说明:返回指向dest的void *指针
参数说明:dest,source分别为目标串和源串的首地址。count为要移动的字符的个数
函数说明:memmove用于从source拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。
- void *MemMove(void *dest,const void *src,size_t n)
- {
- if(n == 0)
- return 0;
- if(dest == NULL)
- return 0;
- if(src == NULL)
- return 0;
- char *psrc = (char*)src;
- char *pdest = (char*)dest;
- //检查是否有重叠问题
- if((dest <= psrc) || (pdest >= psrc+n))
- {
- //正向拷贝--Non-Overlapping Buffers copy from lower addresses to higher addresses
- for(int i=0;i<n;i++)
- {
- *pdest = *psrc;
- psrc++;
- pdest++;
- }
- }
- else
- {
- //反向拷贝--Overlapping Buffers copy from higher addresses to lower addresses
- psrc += n;
- pdest += n;
- for(int i=0;i<n;i++)
- {
- psrc--;
- pdest--;
- *pdest = *psrc;
- }
- }
- return dest;
- }
2.memcpy
函数原型:void *memcpy(void *dest, const void *source, size_t count);
返回值说明:返回指向dest的void *指针
函数说明:memcpy功能和memmove相同,但是memcpy中dest和source中的区域不能重叠,否则会出现未知结果。
- void *MemCopy(void *dest,const void *src,size_t n)
- {
- if(NULL == dest)
- return 0;
- if(NULL == src)
- return 0;
- char *pdest = (char*)dest;
- char *psrc = (char*)src;
- while(n--) //不对是否存在重叠区域进行判断
- *pdest++ = *psrc++; //*pdest++相当于*(pdest++)--先取*pdest,再pdest++
- return dest;
- }
3.两者区别
函数memcpy() 从source 指向的区域向dest指向的区域复制count个字符,如果两数组重叠,不定义该函数的行为。
而memmove(),如果两函数重叠,赋值仍正确进行。
memcpy函数假设要复制的内存区域不存在重叠,如果你能确保你进行复制操作的的内存区域没有任何重叠,可以直接用memcpy;
如果你不能保证是否有重叠,为了确保复制的正确性,必须用memmove。
测试程序(其中用到了上面的两个函数及对应的库函数):
- //该程序在gcc下编译验证
- #include <string.h>
- #include <stdio.h>
- int main()
- {
- int a[10];
- for(int i=0; i < 10; i++)
- a[i] = i;
- MemCopy(&a[4],a,sizeof(int)*6); //结果为:0 1 2 3 0 1 2 3 0 1
- //memcpy(&a[4], a, sizeof(int)*6); //结果为:0 1 2 3 0 1 2 3 0 1(vc下和下面一个相同)
- //MemMove(&a[4],a,sizeof(int)*6); //结果为:0 1 2 3 0 1 2 3 4 5
- //memmove(&a[4],a,sizeof(int)*6); //结果为:0 1 2 3 0 1 2 3 4 5
- //MemMove(a,&a[4],sizeof(int)*6); //结果为:4 5 6 7 8 9 6 7 8 9
- //memmove(a, &a[4], sizeof(int)*6);//结果为:4 5 6 7 8 9 6 7 8 9
- //memcpy(a, &a[4], sizeof(int)*6); //结果为:4 5 6 7 8 9 6 7 8 9
- //MemCopy(a,&a[4],sizeof(int)*6); //结果为:4 5 6 7 8 9 6 7 8 9
- for(i = 0; i < 10; i++)
- printf("%d ",a[i]);
- printf("/n");
- return 0;
- }
程序分析:
这两个函数的函数原型(除了名字)是一样的:
void *memcpy(void *dst, const void *src, size_t count):
void *memmove(void *dst, const void *src, size_t count);
它们都是从src所指向的内存中复制count个字节到dst所指内存中,并返回dst的值。当源内存区域和目标内存区域无交叉时,两者的结果都是一样的。但有交叉时不一样。源内存和目标内存交叉的情况有以下两种:(左边为低地址)
1、
即:dst<=src 且 dst+count>src
2、
即:src<dst且src+count>dst
下面将针对这两种情况来讨论。针对第一种交叉情况情况,dst<src且dst+count>src,memcpy和memmove的结果是一样的。请看下面的例子讲解:
int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
memcpy(a, a+4, sizeof(int)*6);和memmove(a, a+4, sizeof(int)*6);结果是:
4567896789
针对第二种情况,src<dst且src+count>dst,memcpy和memmove的结果是不一样的。请看下面的例子:
int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
memcpy(a+4, a, sizeof(int)*6)
memmove(a+4, a, sizeof(int)*6)
上面图示来自 http://hi.baidu.com/lkmoses/blog/item/3c553dc4778701169c163d57.html
总结:
两者的功能基本相同,唯一不同的是,当 dest 和 src 有重叠的时候选用不同的函数可能会造成不同的结果。
对比上面执行结果,不难得出以下结论:
1. 当 src 和 dest 所指内存区有重叠时,memmove 相对 memcpy 能提供保证:保证能将 src 所指内存区的前 n 个字节正确的拷贝到 dest 所指内存中;
2. 当 src 地址比 dest 地址低时,两者结果一样。换句话说,memmove 与 memcpy 的区别仅仅体现在 dest 的头部和 src 的尾部有重叠的情况下;
即:从高向低复制都可以,从低向高复制用memmove()
memcpy的返回值设计成void *是有目的的,是便于嵌套使用memcpy、memmove等函数。