博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

C语言实现memcpy和memmove

Posted on 2014-09-08 20:23  猫少侠  阅读(934)  评论(0编辑  收藏  举报

0.两者比较:

  memmove用于从src拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中但复制后src内容会被更改但是当目标区域与源区域没有重叠则和memcpy函数功能相同

  memmove在copy两个有重叠区域的内存时可以保证copy的正确,而memcopy就不行了,但memcopy比memmove的速度要快一些,如:
char s[] = "1234567890";
char* p1 = s;
char* p2 = s+2;
  memcpy(p2, p1, 5)与memmove(p2, p1, 5)的结果就可能是不同的,memmove()可以将p1的头5个字符"12345"正确拷贝至p2,而memcpy()的结果就不一定正确了。

1.memcpy

首先是memcpy:

 1 #ifndef MEMCPY_H
 2 #define MEMCPY_H
 3 
 4 #include <stdio.h>
 5 
 6 void *cat_memcpy(void *dst, const void *src, size_t n) {
 7     if (NULL == dst || NULL == src)
 8         return NULL;
 9 
10     char *d = (char *)dst;
11     const char *s = (const char *)src;
12 
13     while (n--)
14         *d++ = *s++;
15 
16     return dst;
17 }
18 
19 #endif

 

 

2.memmove:

  memcpy与memmove的目的都是将N个字节的源内存地址的内容拷贝到目标内存地址中。

  但当源内存和目标内存存在重叠时,memcpy会出现错误memmove能正确地实施拷贝,但这也增加了一点点开销。

memmove的处理措施:

(1)当源内存的首地址等于目标内存的首地址时,不进行任何拷贝

(2)当源内存的首地址大于目标内存的首地址时,实行正向拷贝

(3)当源内存的首地址小于目标内存的首地址时,实行反向拷贝

-- memmove实现

 1 #ifndef MEMMOVE_H
 2 #define MEMMOVE_H
 3 
 4 /*********************************************************************
 5 memcpy与memmove的目的都是将N个字节的源内存地址的内容拷贝到目标内存地址中
 6 
 7 但当源内存和目标内存存在重叠时,memcpy会出现错误,
 8 而memmove能正确地实施拷贝,但这也增加了一点点开销。
 9 
10 memmove的处理措施:
11 (1)当源内存的首地址等于目标内存的首地址时,不进行任何拷贝
12 (2)当源内存的首地址大于目标内存的首地址时,实行正向拷贝
13 (3)当源内存的首地址小于目标内存的首地址时,实行反向拷贝
14 
15 内存的5种情况:
16 (1)内存低端 <-----s-----> <-----d-----> 内存高端 start at end of s
17 (2)内存低端 <-----s--<==>--d----->      内存高端 start at end of s
18 (3)内存低端 <-----sd----->              内存高端 do nothing
19 (4)内存低端 <-----d--<==>--s----->      内存高端 start at beginning of s
20 (5)内存低端 <-----d-----> <-----s-----> 内存高端 start at beginning of s
21 *********************************************************************/
22 
23 
24 #include <stdio.h>
25 
26 void *cat_memmove(void *dst, const void *src, size_t n) {
27     if (NULL == dst || NULL == src || 0 == n)
28         return NULL;
29 
30     char *d = (char *)dst;
31     const char *s = (const char *)src;
32 
33     
34     if (s > d) {       // (2)当源内存的首地址大于目标内存的首地址时,实行正向拷贝
35         while (n--)
36             *d++ = *s++;
37     } else if (s < d){ // (3)当源内存的首地址小于目标内存的首地址时,实行反向拷贝
38         d = d + n - 1; // move to end
39         s = s + n - 1; // move to end
40         while (n--)
41             *d-- = *s--;
42     }
43     // (1)当源内存的首地址等于目标内存的首地址时,不进行任何拷贝
44     // do nothing
45 
46     return dst;
47 }
48 
49 #endif

 

src和dst的内存示意图,5种情况自己在纸上画画就很容易明白的!):

(1)内存低端 <-----s-----> <-----d-----> 内存高端 start at end of s
(2)内存低端 <-----s--<==>--d----->      内存高端 start at end of s
(3)内存低端 <-----sd----->              内存高端 do nothing
(4)内存低端 <-----d--<==>--s----->      内存高端 start at beginning of s
(5)内存低端 <-----d-----> <-----s----> 内存高端 start at beginning of s

 可以看到(1)、(2)处理方法一样;(4)、(5)处理方法一样。

 

main:测试代码:

 1 #include "memcpy.h"
 2 #include "memmove.h"
 3 
 4 void test_memcpy();
 5 void test_memmove();
 6 
 7 int main() {
 8 
 9     test_memmove();
10 
11     return 0;
12 }
13 
14 void test_memcpy() {
15     char dst[64] = {0};
16     char *src = "test memcpy";
17     char *ret = (char *)cat_memcpy(dst, src, strlen(src) + 1);
18     char *ret1 = (char *)cat_memcpy(dst, src, strlen(src));
19     printf("%s\n%s\n%s\n", ret, dst, ret1);
20 }
21 
22 void test_memmove() {
23     char dst[64] = { 0 };
24     char *src = "test cat_memmove";
25     char *ret = (char *)cat_memmove(dst, src, strlen(src) + 1);
26     char *ret1 = (char *)cat_memmove(dst, src, strlen(src));
27     printf("%s\n%s\n%s\n", ret, dst, ret1);
28 
29     printf("\n====================================\n[src<dst]:\n");
30     char s[] = "1234567890";
31     char* p1 = s;
32     char* p2 = s + 2;
33     char *sRet = (char *)cat_memmove(p2, p1, 5);
34     printf("memmove:\n%s\n%s\n%s\n\n", sRet, p1, p2);
35 
36     char s1[] = "1234567890";
37     char* p11 = s1;
38     char* p22 = s1 + 2;
39     char *sRet1 = (char *)cat_memcpy(p22, p11, 5);
40     printf("memcpy:\n%s\n%s\n%s\n", sRet1, p11, p22);
41 
42     printf("\n====================================\n[src>dst]:\n");
43     char ss[] = "1234567890";
44     char* pp1 = ss;
45     char* pp2 = ss + 2;
46     char *ssRet = (char *)cat_memmove(pp1, pp2, 5);
47     printf("memmove:\n%s\n%s\n%s\n\n", ssRet, pp1, pp2);
48 
49     char ss1[] = "1234567890";
50     char* pp11 = ss1;
51     char* pp22 = ss1 + 2;
52     char *ssRet1 = (char *)cat_memcpy(pp11, pp22, 5);
53     printf("memcpy:\n%s\n%s\n%s\n", ssRet1, pp11, pp22);
54 }

 

 

 

 ref:

http://www.cnblogs.com/kekec/archive/2011/07/22/2114107.html

http://blog.chinaunix.net/uid-22780578-id-3346391.html