zoukankan      html  css  js  c++  java
  • C/C++之Memcpy and memmove

    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 = '';
    15 return dst;
    16 }

    Memcpy and memmove - 兰花草 - 兰花草的博客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 = '';
    14 }else if(sp<dp)//重叠 (此时条件 sp<dp<(sp+n))如果sp==dp则快速的返回
    15 {//反向拷贝
    16 sp += n;
    17 dp += n;
    18 *dp = '';
    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的长度,这是调用者应该考虑的问题。

  • 相关阅读:
    paste DEMO合并文件
    diff 文件比较
    grep DEMO
    tr DEMO
    uniq DEMO
    sort DEMO
    定义提示符 PS1 PS4
    MAVEN修改localRepository不起作用
    java数组初始化
    oracle监听服务无法打开
  • 原文地址:https://www.cnblogs.com/ht-927/p/4726351.html
Copyright © 2011-2022 走看看