C语言模拟实现memcpy和memmove

来源:互联网 发布:淘宝收货地址怎么改 编辑:程序博客网 时间:2024/05/21 07:14

memcpy和memmove的作用以区别

memcpy和memmove都是C语言中的库函数,包含于头文件string.h中。要弄清它们的作用,可以查看一下它们的原型。
先来看看memcpy函数:

void * memcpy ( void * destination, const void * source, size_t num );

手册上对memcpy函数的说明如下:

Copy block of memory
Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination.

我们可以看出memcpy的作用是把source指针指向的位置处的num个字节的内存块拷贝到destination指针指向的位置处。不允许源指针和目的指针指向的内存区域有重叠,因为可能会不安全。
再看看memmove函数:

void * memmove ( void * destination, const void * source, size_t num );

手册上对memmove函数的说明如下:

Move block of memory
Copies the values of num bytes from the location pointed by source to the memory block pointed by destination. Copying takes place as if an intermediate buffer were used, allowing the destination and source to overlap.

我们可以看出和memcpy一样,memmove也可以把source指针指向的位置处的num个字节的内存块拷贝到destination指针指向的位置处。和memcpy不一样的是,memmove拷贝的时候会以一段缓冲区作为媒介,所以允许源指针和目的指针指向的内存区域有重叠。
基本它们的不同特性,我们常常认为memcpy是内存块拷贝函数,memmove是内存块移动函数。
为了避免溢出错误,memcpy和memmove函数的源指针指向的数组长度和目的指针指向的数组长度都至少要为num个字节才行。

内存重叠

下面举个例子说明一下内存重叠是什么意思:
这里写图片描述
当我们想把2 3 4 5拷贝到4 5 6 7处去的时候,这两块区域就发生了重叠,如果使用memcpy的话,我们会发现2和3已经替代了4和5,我们没有办法再把4和5拷到6和7处去了,结果就变成了1 2 3 2 3 2 3 8,而这不是我们想要的结果;但是使用memmove的话,我们还是可以得到1 2 3 2 3 4 5 8。
不难发现,上面那个例子如果是从后往前拷的话就不会发生那样的问题,再进一步总结可以发现,只要目的地址在源地址之前就不会出现问题,可以从前往后拷;若目的地址在源地址之后可能会有问题,需要从后往前拷。

代码实现

//模拟实现memcpyvoid* Memcpy(void* des, const void* src, size_t num){    if (des == NULL || src == NULL)        return NULL;    char* desStr = (char*)des;    const char* srcStr = (const char*)src;    while (num)    {        *desStr++ = *srcStr++;        --num;    }    return des;}//模拟实现memmovevoid* Memmove(void* des, const void* src, size_t num){    if (des == NULL || src == NULL)        return NULL;    char* desStr = (char*)des;    const char* srcStr = (const char*)src;    if (des < src)   //目的地址在源地址之前,从前往后拷    {        while (num--)        {            *desStr++ = *srcStr++;        }    }    else   //目的地址在源地址之后,从后往前拷    {        while (num--)        {            *(desStr + num) = *(srcStr + num);        }    }    return des;}

测试用例:

void test(){    int i = 0;    int arr1[] = { 1, 2, 3, 4, 5, 6, 7, 8 };    int arr2[] = { 1, 2, 3, 4, 5, 6, 7, 8 };    Memcpy(arr1, arr1+3, 4*sizeof(int));    Memmove(arr2 + 3, arr2 + 1, 4 * sizeof(int));    for (i = 0; i < 8; i++)    {        printf("%d ", arr1[i]);    }    printf("\n");    for (i = 0; i < 8; i++)    {        printf("%d ", arr2[i]);    }    printf("\n");}