C memmove() 语法
memmove() 是 C 语言 <string.h> 标准库的一个内置函数,用于从一个内存区域复制 “指定数量的字节” 到另一个内存区域。
memmove() 与 memcpy() 类似,但它们之间有一个重要的区别:memmove() 能够正确处理 “源内存区域” 和 “目标内存区域” 重叠的情况。
语法:
memmove(dest, src, n)说明:
memmove() 函数接收以下 3 个参数。
dest(void*):指向目标内存区域的指针。这是一个 void* 指针,表示它可以指向任何类型的数据。目标内存区域必须有足够的空间来容纳 n 个字节。src(const void*):指向源内存区域的指针。这是一个 const void* 指针,表示它指向的数据不会被修改。n(size_t):要复制的字节数。
memmove(dest, src, n) 会从 src 指向的内存位置开始,复制 n 个字节到 dest 指向的内存位置。memmove() 的复制是以 “字节” 为单位进行的,它不关心 “源内存区域” 和 “目标内存区域” 中存储的数据类型。
提示: memmove 是 “memory move” 的缩写。
C memmove() 摘要
| 使用频率 | 高 |
|---|---|
| 修改字符串 | 是 |
| 官方文档 | 查看 |
C memmove() 示例
接下来,我们通过几个简单的例子来讲解一下 C memmove() 函数是如何使用的。
示例 1:memmove() 在同一个数组中移动数据 ( 重叠 )
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[] = "abcdefg"; // 字符串长度为 7 + 1 ( 终止符 ) = 8 字节
printf("原始字符串:%s\n", str);
// 使用 memmove() 将 "defg" 移动到 "bcdefg" 的位置
// 源地址 : str + 3 ( 指向 'd')
// 目标地址 : str + 1 ( 指向 'b')
// 复制数量 : 4 字节 ("defg") + 1 字节 ('\0') = 5 字节
memmove(str + 1, str + 3, 5);
printf("结果字符串:%s\n", str);
return 0;
}运行结果如下。
原始字符串:abcdefg
结果字符串:adefg分析:
在这个例子中,我们展示了如何使用 memmove() 处理重叠内存。我们将字符串的一部分("defg",包含终止符)移动到同一个字符串的另一个位置。源地址 (str + 3) 和目标地址 (str + 1) 的内存区域是重叠的。
memmove() 确保在将数据写入目标位置时,不会覆盖尚未读取的源数据,从而正确地完成了移动操作。如果在这里使用 memcpy(),结果将是未定义的,很可能会出错。
示例 2:memmove() 在同一个数组中向前移动数据 ( 重叠 )
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[] = "abcdefg";
printf("原始字符串: %s\n", str);
// 使用 memmove() 将 "abcde" 移动到 "bcde" 的位置
// 源地址 : str ( 指向 'a')
// 目标地址 : str + 1 ( 指向 'b')
// 复制数量 : 6 字节 (即 'a', 'b', 'c', 'd', 'e', 'f')
memmove(str + 1, str, 6);
printf("结果字符串: %s\n", str);
return 0;
}运行结果如下。
原始字符串 : abcdefg
结果字符串 : aabcdef分析:
memmove() 同样能够正确处理在同一个数组中向前移动数据时的重叠情况,将源区域的数据完整地复制到目标区域。
示例 3:将数据复制到不重叠的内存区域
#include <stdio.h>
#include <string.h>
int main(void)
{
int src[] = {10, 20, 30, 40, 50};
int dest[5];
size_t length = sizeof(src);
// 使用 memmove 复制整个数组 ( 不重叠 )
memmove(dest, src, length);
printf("源数组: ");
for (size_t i = 0; i < 5; i++) {
printf("%d ", src[i]);
}
printf("\n");
printf("目标数组: ");
for (size_t i = 0; i < 5; i++) {
printf("%d ", dest[i]);
}
printf("\n");
return 0;
}运行结果如下。
源数组 : 10 20 30 40 50
目标数组 : 10 20 30 40 50分析:
当源内存区域和目标内存区域不重叠时,memmove() 的行为与 memcpy() 相同。在这个例子中,源数组和目标数组是不同的内存块,两者不重叠,memmove() 完成了正确的复制。
memcpy() 与 memmove() 的区别
memcpy() 和 memmove() 都可以用于复制字节块,但它们在处理 “重叠内存区域” 时的行为是不同的。
memcpy():它的行为在 “源内存区域” 和 “目标内存区域” 重叠时是未定义的。在内存重叠的情况下使用 memcpy(),可能会导致数据被错误地复制,因为目标区域在复制过程中可能覆盖尚未读取的源区域数据。memmove():它被设计用来正确处理 “源内存区域” 和 “目标内存区域” 重叠的情况。memmove() 会确保在将数据复制到目标区域之前,先将源区域的数据完全读取或暂存起来,从而避免数据损坏。其中,memmove() 在处理重叠区域时可能比 memcpy() 效率稍低。
如果能够确定 “源内存区域” 和 “目标内存区域“ 不重叠,我们可以考虑使用 memcpy(),因为它的效率更高。如果 “源内存区域” 和 “目标内存区域“ 可能存在重叠,或者不确定是否重叠,则我们应该始终使用更安全的 memmove() 函数。
