您的位置:首页 > 编程语言 > C语言/C++

C语言函数_string.h 之 内存copy函数memmove

2015-05-01 22:26 627 查看
       上一篇文章用C语言实现了最简单(逐字节复制)的内存复制函数memcpy(),但memcpy()函数有一个问题是:不能保证src和dest所指内存区域不会出现重叠的情况,没有重叠区域,只能靠程序员来保证。所谓的内存重叠,就是复制的目的地址的首地址出现在源地址范围内,如下图:上面的表示没有内存重叠,下面的则表示有内存重叠


【图片来自网上】
程序例子,比如:

char p[20] = "abcdefghijk";
memcpy(&p[3], p, 5);
printf(“%s", &p[3]);


       那么&p[3]串的值就会变成"abcabijk",为什么红色部分会是abcab呢,因为p[3]-p[5]的值已经变成了“abc”,因为内存重叠,所以memcpy()函数就会得到错误的结果,虽然程序运行时并不会崩溃。事实上,无论是VS还是GCC,它们的库函数memcpy都已经处理了内存重叠的问题,在GCC编译器下,上面代码得出的结果是"abcdeijk"。

在这篇文章中介绍另一个内存复制函数memmove(),它将会处理内存重叠的问题。

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

函数功能:由src所指的内存区域复制count个字节到dest所指的内存区域

memmove()处理内存重叠的方法:如果出现内存重叠,则从待复制数据片段的末端开始复制;否则像memcpy()一样操作

代码:

void * memmove( void *dest, const void *src, size_t count)
{
assert((NULL != dest) && (NULL != source));
void *ret = dest;
if( dest <= src || (char*)dest >= ((char*)src + count))
{
while( count --)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
dest = (char*)dest + count - 1;
src = (char*)src + count - 1;
while( count --)
{
*(char*)dest = *(char*)src;
dest = (char*)dest - 1;
src = (char*)src - 1;
}
}
return ret;
}
        程序先判断目的地址和源地址是否有重叠,判断表达式为:dest
<= src || (char*)dest >= ((char*)src + count),由此看来上面对“内存重叠”的理解有bug,因为当dest == src的时候dest也算是在src的范围内,但这是没关系的,复制的结果就是把同一个地址上的值置为相同的一个值。当上表达式成立的时候,执行相当于memcpy()函数的功能。如果存在内存重叠,则从需要复制的内存末端开始复制,如下图中下面部分,内存重叠部分为3-4两个字节部分,其实count是5,那么从末端开始时,src就应该从src+count-1=4的位置开始,dst就应该从dst+count-1=7的位置开始。所以:4->7,
3->6, 2->5, 1->4, 0->3(a->b表示把a内存的值赋给b内存地址),明显地看到,4->7, 3->6已经把src中3,4的值存放在dst上了,当把地址0,1的内容赋给地址3,4的时候不会对dst上6,7的内容造成影响,虽然原来的数据不再是原来的数据(dest+size>=src),但拷贝的数据是原来的数据,所以得到的结果是正确的。



与memcpy()的区别

    1、函数memcpy() 从src 指向的区域向dest指向的区域复制count个字符,如果两内存有重叠,则该函数的行为是未定义的;而memmove(),如果两内存存在重叠时,赋值仍正确进行。

    2、memcpy函数假设要复制的内存区域不存在重叠,如果你能确保你进行复制操作的的内存区域没有任何重叠,可以直接用memcpy;如果你不能保证是否有重叠,为了确保复制的正确性,你必须用memmove。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息