深入理解 `memmove`:从标准库到自己动手实现

在这里插入图片描述

🚀个人主页:BabyZZの秘密日记
📖收入专栏:C语言


在日常的 C/C++ 编程中,内存操作函数是不可或缺的工具。memcpymemsetmemmove 这些函数为我们提供了高效的内存操作能力。今天,我们将深入探讨 memmove 这个函数,理解它的工作原理,并尝试自己实现一个功能相同的 my_memmove

什么是 memmove

memmove 是 C 标准库 <string.h> 中的一个函数,其原型为:

void *memmove(void *dest, const void *src, size_t n);

它的作用是将 src 指向的内存区域的 n 个字节复制到 dest 指向的内存区域。与 memcpy 不同的是,memmove 能够正确处理源内存区域和目标内存区域重叠的情况。

为什么需要 memmove

考虑以下场景:

int arr[] = {1, 2, 3, 4, 5};
// 将 arr[0..3] 移动到 arr[1..4]
memmove(arr + 1, arr, 4 * sizeof(int));

如果使用 memcpy,由于源和目标区域重叠,可能会导致未定义行为(如数据被覆盖)。memmove 通过智能地选择复制方向(从前向后或从后向前)来避免这种问题。

标准库 memmove 的使用示例

让我们先看一个简单的使用示例:

#include <stdio.h>
#include <string.h>

int main()
{
    int arr1[] = {1, 2, 3, 4, 5};
    int arr2[5] = {0};
    int sz = sizeof(arr2) / sizeof(arr2[0]);
    
    // 使用标准库 memmove
    memmove(arr2, arr1, sizeof(arr1));
    
    for (int i = 0; i < sz; i++)
    {
        printf("%d ", arr2[i]);
    }
    return 0;
}

输出:

1 2 3 4 5

实现自己的 my_memmove

现在,我们来尝试实现一个功能相同的 my_memmove。关键点在于正确处理内存重叠的情况。

实现思路

  1. 参数检查:确保 destsrc 不为 NULL
  2. 重叠判断:如果 destsrc 之前,从前向后复制;否则从后向前复制。
  3. 逐字节复制:使用 unsigned char* 进行逐字节操作,确保通用性。

代码实现

#include <stdio.h>
#include <assert.h>

void* my_memmove(void* dest, const void* src, size_t num)
{
    assert(dest && src); // 确保指针有效
    
    unsigned char* e1 = (unsigned char*)dest;
    const unsigned char* e2 = (const unsigned char*)src;
    
    if (e1 < e2)
    {
        // 从前向后复制
        while (num--)
        {
            *e1++ = *e2++;
        }
    }
    else
    {
        // 从后向前复制
        while (num--)
        {
            *(e1 + num) = *(e2 + num);
        }
    }
    
    return dest; // 注意:应返回原始 dest 指针
}

int main()
{
    int arr1[] = {1, 2, 3, 4, 5};
    int arr2[5] = {0};
    int sz = sizeof(arr2) / sizeof(arr2[0]);
    
    // 使用自定义 my_memmove
    my_memmove(arr2, arr1, sizeof(arr1));
    
    for (int i = 0; i < sz; i++)
    {
        printf("%d ", arr2[i]);
    }
    return 0;
}

注意事项

  1. 返回值:标准库的 memmove 返回 dest 指针。在我们的实现中,注意 return e1; 是错误的,因为 e1 已经被修改。应改为 return dest;
  2. 重叠处理if (e1 < e2) 的比较是基于 unsigned char* 的指针值,这是正确的,因为指针比较的是地址。

测试重叠情况

让我们测试一下重叠情况:

int main()
{
    int arr[] = {1, 2, 3, 4, 5};
    
    // 将 arr[0..3] 移动到 arr[1..4]
    my_memmove(arr + 1, arr, 4 * sizeof(int));
    
    for (int i = 0; i < 5; i++)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}

输出:

1 1 2 3 4

总结

通过今天的探讨,我们深入理解了 memmove 的工作原理,并亲手实现了一个功能相同的 my_memmove。关键点在于正确处理内存重叠的情况,确保数据的正确复制。希望这篇文章能帮助你更好地理解和使用内存操作函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值