🚀个人主页:BabyZZの秘密日记
📖收入专栏:C语言
在日常的 C/C++ 编程中,内存操作函数是不可或缺的工具。memcpy
、memset
、memmove
这些函数为我们提供了高效的内存操作能力。今天,我们将深入探讨 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
。关键点在于正确处理内存重叠的情况。
实现思路
- 参数检查:确保
dest
和src
不为NULL
。 - 重叠判断:如果
dest
在src
之前,从前向后复制;否则从后向前复制。 - 逐字节复制:使用
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;
}
注意事项
- 返回值:标准库的
memmove
返回dest
指针。在我们的实现中,注意return e1;
是错误的,因为e1
已经被修改。应改为return dest;
。 - 重叠处理:
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
。关键点在于正确处理内存重叠的情况,确保数据的正确复制。希望这篇文章能帮助你更好地理解和使用内存操作函数。