Technorati 标签: memcpy, memmove

首先看下man的结果:

NAME
       memcpy - copy memory area

SYNOPSIS
       #include <string.h>

       void *memcpy(void *dest, const void *src, size_t n);

DESCRIPTION
       The  memcpy()  function  copies  n bytes from memory area src to memory
       area dest.  The memory areas should not overlap.  Use memmove(3) if the
       memory areas do overlap.

 

NAME
       memmove - copy memory area

SYNOPSIS
       #include <string.h>

       void *memmove(void *dest, const void *src, size_t n);

DESCRIPTION
       The  memmove()  function  copies n bytes from memory area src to memory
       area dest.  The memory areas may overlap: copying takes place as though
       the  bytes in src are first copied into a temporary array that does not
       overlap src or dest, and the bytes are then copied from  the  temporary
       array to dest.
可以看到两者最大的区别就是src和dest区域重叠的情况,当重叠时,可以使用memmove。

 

先看下memcpy的代码:

   1: void *memcpy(void *dest, const void *src, size_t n)
   2: {
   3:     void* ret = dest;
   4:  
   5:     //从低地址向高地址依次复制
   6:     while (n--)
   7:     {
   8:         *(char*)(dest++) = *(char*)(src++);
   9:     }
  10:  
  11:     return ret;
  12: }

而对于重叠的情况:

1.dest地址比src低,可以类似于不重叠即memcpy的方式复制,比如:

   1: char a[] = "helloworld";
   2: printf("%s\n", a);
   3: memcpy(a, a+2, 3);
   4: printf("%s\n", a);

从a[2]开始复制3个字符,到a[0]处依次放下。

输出:lloloworld

2.src地址比dest地址低,如果采用memcpy的方式复制,则会出错,比如:

   1: char a[] = "helloworld";
   2: printf("%s\n", a);
   3: memcpy(a+2, a, 3);
   4: printf("%s\n", a);

原意是从a[0]开始复制3个字符,到a[2]处依次放下,则为hehelworld

但是输出:hehehworld

正确的代码:

   1: void *memmove(void* dest, const void *src, size_t n)
   2: {
   3:     void* ret = dest;
   4:  
   5:     if (dest<=src || (char*)dest>= ((char*)src + n))
   6:     {
   7:         //当dest地址低于src,或者两者内存区域无重叠
   8:         while (n--)
   9:         {
  10:             *(char*)(dest++) = *(char*)(src++);
  11:         }
  12:     }
  13:     else
  14:     {
  15:         //src地址低于dest时
  16:         //如果仍由低到高复制,dest会覆盖掉src的内容
  17:         //改为由高地址到低地址复制
  18:         dest = (char*)dest + n - 1;
  19:         src  = (char*)src  + n - 1;
  20:         while (n--)
  21:         {
  22:             *(char*)(dest--) = *(char*)(src--);
  23:         }
  24:     }
  25:  
  26:     return ret;
  27: }

这样调用memove(a+2, a, 3)才是正确的。

输出:hehelworld