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

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

memmove的处理措施:

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

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

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

-- memcpy实现

 
1 voidmemcpy(void* dest, const void* src, size_t n)
2 {
3 char* d = (char*) dest;
4 const char* s = (const char*) src;
5 while(n-–)
6 *d++ = *s++;
7 return dest;
8 }

 

Notes:

  • memcpy的参数指针类型是void*,具体赋值操作是以字节为单位。
  • 必须进行类型转换。
  • 返回的还是void*型的dest。

-- memmove实现

 
01 voidmemmove(void* dest, const void* src, size_t n)
02 {
03 char* d = (char*) dest;
04 const char* s = (const char*) src;
05  
06 if (s>d)
07 {
08 // start at beginning of s
09 while (n--)
10 *d++ = *s++;
11 }
12 else if (s<d)
13 {
14 // start at end of s
15 d = d+n-1;
16 s = s+n-1;
17  
18 while (n--)
19 *d-- = *s--;
20 }
21 return dest;
22 }

 示意图:

(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 Notes:
  • s==d时,什么都不做。
  • d在前,正向拷贝。
  • d在后,逆向拷贝。

1.memmove

函数原型:void *memmove(void *dest, const void *source, size_t count)

返回值说明:返回指向dest的void *指针

参数说明:dest,source分别为目标串和源串的首地址。count为要移动的字符的个数

函数说明:memmove用于从source拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。

2.memcpy

函数原型:void *memcpy(void *dest, const void *source, size_t count);

返回值说明:返回指向dest的void *指针

函数说明:memcpy功能和memmove相同,但是memcpy中dest和source中的区域不能重叠,否则会出现未知结果。
原型:extern char *strcpy(char *dest,char *src);  功能:把src所指由NULL结束的字符串复制到dest所指的数组中。  说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串,返回指向dest的指针。

  其实在strcpy的实现比较多,但思想是一致的,一般用C来实现,但是memcpy和memmove这样的函数可能是用汇编实现的,并且充分利用块拷贝的思想,不会单字节单字节的拷贝。所以效率strcpy<memcpy.

memmove一般由于要判断内存是否重合,效率也会较memcpy低些。

1 /***
2 * @brief 以字节的方式直接拷贝
3 * 库中实现是以汇编实现,
4 * 其实可以直接调用strncat函数
5 * **/
6 void *memcpy(void *dst,void *src,size_t n)
7 {
8 char *dp = (char *)dst;
9 char *sp = (char *)src;
10 assert((src!=0)&&(dst!=0)&&(n>0));//not null
11 while(n--)
12 *(dp++) = *(sp++);
13 /**!边界*/
14 dp = '\0';
15 return dst;
16 }

memmove

 1 void *memmove(void *dst,const void *src,int n)                                                
2 {
3 char *dp = (char *)dst;
4 char *sp = (char *)src;
5 assert((src!=0)&&(dst!=0)&&(n>0));//not null
6 //非重叠
7 //dp < sp
8 //dp > (sp+n)
9 if(dp<sp||(sp+n)>=dp)
10 {
11 while(n--)
12 *(dp++) = *(sp++);
13 *dp = '\0';
14 }else if(sp<dp)//重叠 (此时条件 sp<dp<(sp+n))如果sp==dp则快速的返回
15 {//反向拷贝
16 sp += n;
17 dp += n;
18 *dp = '\0';
19 while(n--)
20 *(--dp) = *(--sp);
21 }
22 return dst;
23 }

 注意对于重合的要反向拷贝


/*
 *Magicman
 *myMemcpy.c
 *不调用库函数,实现内存拷贝
*/

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

void *myMemcpy(void *dest, const void *src, int len)
{
    assert((dest != NULL) && (src != NULL) && (len >= 0));

    if (dest == src)
    {
        return dest;
    }

    while (len-- > 0)
    {
        *(char *)dest++ = *(char *)src++;
    }

    return dest;
}

int main(int argc, char argv[])
{
    char str[20] = "Testing myMemory!";
    char pstr[20] = "";
    char *pp = str;
    int ia[10] = {1,2,3,4,5,6,7,8,9,10};
    int ib[10] = {};
    int *ip = NULL;

myMemcpy((void *)pstr, (void *)str, sizeof(str));

printf("%s/n", pstr);

printf("%s/n", myMemcpy((void *)pp, (void *)str, 20));

myMemcpy((void *)ib, (void *)ia, 5*sizeof(int));

for (ip = ib; ip < ib + 10; ip++)
    {
        printf("%d  ", *ip);
    }

printf("/n");
    
    return 0;
}


让自己实现memcpy库函数,要求考虑特殊情况,两段内存存在覆盖,以及指针为空的情况。

几点结论: 
1,memcpy实现从源source中拷贝n个字节到目标destin中,src源数据应该保留。
2,memmove实现移动一块字节,src源数据可以不保留。
3,memcpy没有考虑内存覆盖问题(由assert条件可知);而memmove考虑了内存覆盖问题,并给出了解决办法。
4,memcpy和memmove中不需要考虑数组越界问题,dst的长度应该大于src的长度,这是调用者应该考虑的问题。

C/C++之Memcpy and memmove的更多相关文章

  1. memcpy vs memmove

    [本文连接] http://www.cnblogs.com/hellogiser/p/memcpy_vs_memmove.html [分析] memcpy与memmove的目的都是将N个字节的源内存地 ...

  2. memcpy与memmove的区别

    在面试中经常会被问道memcpy与memove有什么区别? 整理如下: 其实主要在考C的关键字:restrict C库中有两个函数可以从一个位置把字节复制到另一个位置.在C99标准下,它们的原型如下: ...

  3. C语言实现memcpy和memmove

    0.两者比较: memmove用于从src拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中.但复制后src内容会被 ...

  4. memcpy、memmove、memset及strcpy函数实现和理解

    memcpy.memmove.memset及strcpy函数实现和理解 关于memcpy memcpy是C和C++ 中的内存拷贝函数,在C中所需的头文件是#include<string.h> ...

  5. 关于memcpy和memmove的一点说明

    今天看到书上降到memcpy和memmove的区别才突然发现原来两者之间有如此区别,以前只知道这两个函数是 实现同样的功能,没有接触到其不同. memcpy和memmove在MSDN的定义如下: 从两 ...

  6. strcpy()、memcpy()、memmove()、memset()的内部实现

    一直想知道 strcpy().memcpy().memmove().memset()的内部实现 strcpy(), 字符串拷贝. char *strcpy(char *strDest, const c ...

  7. 第 16 章 C 预处理器和 C 库(string.h 库中的 memcpy() 和 memmove())

    /*----------------------------------------- mems.c -- 使用 memcpy() 和 memmove() ---------------------- ...

  8. 模拟实现memcpy 与 memmove

    模拟实现memcpy 与 memmove 1.str系列的函数只能处理字符串——>必须带有'\0'2.memcpy内存处理函数:不涉及'\0',需要包含头文件 string.h3.source的 ...

  9. memcpy、memmove、memset、memchr、memcmp、strstr详解

    第一部分 综述 memcpy.memmove.memset.memchr.memcmp都是C语言中的库函数,在头文件string.h中.memcpy和memmove的作用是拷贝一定长度的内存的内容,m ...

随机推荐

  1. Des加密(js+java结果一致)【原创】

    des加密算法,javascript版本和java版本 目录: 1.资源文件下载 2.JavaScript文件(des.js) 3.html文件(des.html) 4.java文件(des.java ...

  2. Keepalived指定文件接收日志

    keepalived默认日志接收文件为/var/log/messages不方便查看,可以指定文件接收日志 修改配置文件/etc/sysconfig/keepalived KEEPALIVED_OPTI ...

  3. TOP100summit:【分享实录】爆炸式增长的斗鱼架构平台的演进

    本篇文章内容来自2016年TOP100summit斗鱼数据平台部总监吴瑞城的案例分享. 编辑:Cynthia 吴瑞诚:斗鱼数据平台部总监 曾先后就职于淘宝.一号店. 从0到1搭建公司大数据平台.平台规 ...

  4. Kettle 4.2源码分析第三讲--Kettle 转换机制transformation介绍

    转换机制 每个转换步骤都是ETL数据流里面的一个任务.转换步骤包括输入.处理和输出.输入步骤从外部数据源获取数据,例如文件或者数据库:处理步骤处理数据流,字段计算,流处理等,例如整合或者过滤.输出步骤 ...

  5. mongostat和mongotop对mongodb数据库运行状态进行监控

    --mongostat工具是mongdb自带的监控工具,可以用来监控mongodb当前状态下的运行情况: [root@slave2 ~]# /usr/local/mongodb341/bin/mong ...

  6. 选择排序之python

    选择排序( Selection sort) 1.算法描述: 通过n-i次关键字之间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i(1<=i<=n)个记录进行交换. 对尚未完成排 ...

  7. 不移除通知的话,出现的bug

    没销毁的私聊控制器仍然监听到了通知,发送表情

  8. mysql 内置功能 存储过程介绍

    存储过程介绍 就是mysql内置功能把逻辑写好 的功能给封装好,封装成一个接口名,把接口名丢给应用程序,应用程序直接调用接口名实现一系列增删改查功能 这个接口叫存储过程 基于存储过程封装成一个功能 存 ...

  9. visual studio code 编辑器的配置及快捷键等, vscode, csc

    visual studio code (vsc) 对开发node.js,javascript,python,html,golang等比较友好,同时支持git浏览及分屏对比,运行速度快,所以是值得一用的 ...

  10. js 的each()方法遍历对象和数组

    <script src="../lib/jquery-1.8.3.min.js" ></script> <script type="text ...