C++中memcpy和memmove的区别总结

所属分类: 软件编程 / C 语言 阅读数: 79
收藏 0 赞 0 分享

变态的命名

我们在写程序时,一般讲究见到变量的命名,就能让别人基本知道该变量的含义。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 (dst < 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)对应的情况时,就需要先从src的头部开始复制;也就是memmove源码中的if分支,这部分源码和memcpy的实现是一致的;当出现(2)对应的情况时,就需要先从src的尾部开始复制,防止出现了覆盖现象。这就是memmove比memcpy多的一个考虑点,所以说,在实际使用时,使用memmove是比memcpy更安全的。

总结

总结到了这里,我觉的我已经把问题说清楚了。你说呢?如果你还有什么好的想法,欢迎你和我分享。

更多精彩内容其他人还在看

C++中四种对象生存期和作用域以及static的用法总结分析

以下是对C++中四种对象生存期和作用域以及static的用法进行了详细的介绍,需要的朋友可以过来参考下
收藏 0 赞 0 分享

C++嵌套类与局部类详细解析

从作用域的角度看,嵌套类被隐藏在外围类之中,该类名只能在外围类中使用。如果在外围类之外的作用域使用该类名时,需要加名字限定
收藏 0 赞 0 分享

C++空类详解

以下是对C++中的空类进行了详细的介绍,需要的朋友可以过来参考下
收藏 0 赞 0 分享

C++之友元:友元函数和友元类详解

友元是一种允许非类成员函数访问类的非公有成员的一种机制。可以把一个函数指定为类的友元,也可以把整个类指定为另一个类的友元
收藏 0 赞 0 分享

C++中返回指向函数的指针示例

int (*ff(int)) (int *,int);表示:ff(int)是一个函数,带有一个int型的形参,该函数返回int (*) (int *,int),它是一个指向函数的指针,所指向的函数返回int型并带有两个分别是Int*和int型的形参
收藏 0 赞 0 分享

C数据结构之单链表详细示例分析

以下是对C语言中的单链表进行了详细的分析介绍,需要的朋友可以过来参考下
收藏 0 赞 0 分享

C数据结构之双链表详细示例分析

以下是对c语言中的双链表进行了详细的分析介绍,需要的朋友可以过来参考下
收藏 0 赞 0 分享

浅析如何在c语言中调用Linux脚本

如何在c语言中调用Linux脚本呢?下面小编就为大家详细的介绍一下吧!需要的朋友可以过来参考下
收藏 0 赞 0 分享

深入解析unsigned int 和 int

以下是对unsigned int和int进行了详细的分析介绍,需要的朋友可以过来参考下
收藏 0 赞 0 分享

浅谈C++中的string 类型占几个字节

本篇文章小编并不是为大家讲解string类型的用法,而是讲解我个人比较好奇的问题,就是string 类型占几个字节
收藏 0 赞 0 分享
查看更多