C语言中的内存函数有如下这些

  • memcpy
  • memmove
  • memcmp
  • memset

下面看看memmove函数

memmove

为什么会需要memmove函数?

int main()
{
    int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
    int i = 0;
    // 想把12345 拷贝到 34567上去
    // 应该打印 1 2 1 2 3 4 5 8 9 10
    my_memcpy(arr + 2, arr, 20);

    for (i = 0; i < 10; i++)
    {
    	printf("%d ", arr[i]);
    }
    // 但是输出 1 2 1 2 1 2 1 8 9 10

    return 0;
}

上面会输出 1 2 1 2 1 2 1 8 9 10,我们来看看为什么会出现这样的结果。

我这里画了张图,方便理解。

C语言-内存函数的实现(二)之memmove-LMLPHP

因为拷贝的地方重叠了,使原来的数据(3 4 5)被覆盖了,导致最后出来的结果不是我们想要的。

也就是说,如果拷贝的地方重叠了,那么就会出现这种情况。

那么如何解决呢?答案就是从后往前拷贝,指针从最后的地方开始操作。

还是上一张图

C语言-内存函数的实现(二)之memmove-LMLPHP

这样,就得出了我们想要的结果。

但是呢,也不能一概而论,就全部都是从后往前拷贝,还是得分情况的,具体就是看destinationsource的位置关系。

C语言-内存函数的实现(二)之memmove-LMLPHP

回到最开始的问题,为什么会需要memmove函数?,因为memmove这个函数可以处理这种重叠拷贝。

老规矩,我们还是看看文档是怎样说的,如下

memmove文档

可以看出,memmove和memcpy的唯一区别就是,memmove函数处理的源内存块和目标内存块是可以重叠的。
也就是说,如果源空间和目标空间出现重叠,就得使用memmove函数处理。

实现

void* my_memmove(void* dest, void* src, size_t num)
{
    //dest落在了src的左边,从前往后拷贝
    //dest落在了src的右边,同时没有超过那个重叠的边界的时候,从后往前拷贝
    assert(dest != NULL);
    assert(src != NULL);
    void* rest = dest;
    // void* 不能直接解引用,那么如何复制呢?
    // 给了num个字节,也就是需要复制num个字节
    // 那就转换成char*,一个一个字节的复制过去
    if (dest < src)
    //if (dest < src || dest > (char*)src + num)
    {
    	//dest落在了src的左边,从前往后拷
    	while (num--)
    	{
    	    *(char*)dest = *(char*)src;
    	    //++(char*)dest;
    	    //++(char*)src;
    	    ((char*)dest)++;
    	    ((char*)src)++;
    	}
    }
    else
    {
    	// 从后往前拷
    	// 找到最后一个字节
    	while (num--)
    	{
    	    *((char*)dest + num) = *((char*)src + num);
    	}

    }
    return rest;
}

最后,感谢屏幕前靓仔花宝贵的时间阅读我这篇博客~
本人水平有限,如有错误以及不足之处,欢迎靓仔指出。

04-28 12:12