zoukankan      html  css  js  c++  java
  • memcpy和memmove

    变态的命名

          我们在写程序时,一般讲究见到变量的命名,就能让别人基本知道该变量的含义。memcpy内存拷贝,没有问题;memmove,内存移动?错,如果这样理解的话,那么这篇文章你就必须要好好看看了,memmove还是内存拷贝。那么既然memcpy和memmove二者都是内存拷贝,那二者究竟有什么区别呢?

    先说memcpy

          你有没有好好的参加过一场C++笔试。让你写出memcpy的实现,这是多么常见的笔试题啊。现在,拿起你的演算纸和笔;是的,是笔和纸,不是让你在你的IDE上写。写不出来?看下面吧:

    void *mymemcpy(void *dest, const void *src, size_t count)
    {
        assert(dest != NULL && src != NULL);
    
        char *tmp = (char *)dest;
        char *p = (char *)src;
    
        while (count--)
        {
            *tmp++ = *p++;
        }
        return dest;
    }

    memcpy的实现很简单,一般在笔试时,出现写源码的题目,无非就是需要注意以下几点:

    1. 确定函数原型;
    2. 判断参数合法性;
    3. 逻辑实现(考虑各种情况,统称逻辑实现);
    4. 错误处理。

    当然了,我的这个没有错误处理,也不需要错误处理。上面,我写出了memcpy的实现源码,实现原理如下图所示:
    果冻想 | 一个原创文章分享网站

    这样下去,上面的代码会运行的很好,如果出现下面的情况呢?
    果冻想 | 一个原创文章分享网站

    i、n、k的内存和J、e、l的内存地址重合了,现在再使用上面的代码进行copy时,会出现什么问题呢?你有没有想过这个问题。如果没有,那就现在想想,不急着阅读下面的内容。

    然后,我再留一个问题,上面的代码中,为什么都需要将void *转换成char *呢?比如:

    char *tmp = (char *)dest;

    可以留言回答哦。

    再说memmove

    memmove也是用来实现内存的直接拷贝的。说起这个命名,我个人觉的多少还是有点坑的。既然memmove也是用来内存数据移动的,那就先来看看memmove的实现源码。

    void *mymemmove(void *dest, const void *src, size_t count)
    {
        assert(dest != NULL && src != NULL);
    
        if (dest < src)   //当目的地址小于源地址时,情况一,从源地址的头部开始复制
        {
            char *p = (char *)dest;
            char *q = (char *)src;
            while (count--)
            {
                *p++ = *q++;
            }
        }
        else     //当
        {
            char *p = (char *)dest + count;
            char *q = (char *)src + count;
            while (count--)
            {
                *--p = *--q;
            }
        }
    
        return dest;
    }

    从源码看,memmove的确比memcpy复杂一些;再仔细一看,多了些什么?哦,多了一个else分支,而正是这个else分支,就处理了当src和dest的内存重合的问题。

    memcpy和memmove的比较

    从实现源码中的确能看出一些猫腻,当出现了src和dest的内存有重合的时机时,memmove的处理规则是从后往前进行copy。当然了,重合的问题,需要考虑的以下两种场合。
    果冻想 | 一个原创文章分享网站

    如图所示,

    当出现(1)对应的情况时,即:dest<src; 就需要先从src的头部开始复制;也就是memmove源码中的if分支,这部分源码和memcpy的实现是一致的;

    当出现(2)对应的情况时,即:dest>src; 就需要先从src的尾部开始复制,防止出现了覆盖现象。这就是memmove比memcpy多的一个考虑点,所以说,在实际使用时,使用memmove是比memcpy更安全的。

  • 相关阅读:
    PAT (Advanced Level) Practice 1071 Speech Patterns (25分)
    PAT (Advanced Level) Practice 1070 Mooncake (25分)
    PAT (Advanced Level) Practice 1069 The Black Hole of Numbers (20分)
    PAT (Advanced Level) Practice 1074 Reversing Linked List (25分)
    PAT (Advanced Level) Practice 1073 Scientific Notation (20分)
    第一次冲刺个人总结01
    构建之法阅读笔记01
    人月神话阅读笔记01
    四则运算2
    学习进度条(软件工程概论1-8周)
  • 原文地址:https://www.cnblogs.com/ranjiewen/p/5550085.html
Copyright © 2011-2022 走看看