C memmove() 函数

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() 函数。

上一篇: memcpy()

下一篇: memset()

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号