
🚀个人主页: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。关键点在于正确处理内存重叠的情况,确保数据的正确复制。希望这篇文章能帮助你更好地理解和使用内存操作函数。

1190

被折叠的 条评论
为什么被折叠?



