【C标准库】深入理解 C 语言memmove函数:安全内存拷贝的利器


🌈个人主页:聆风吟_
🔥系列专栏:C语言标准库
🔖少年有梦不应止于心动,更要付诸行动。


文章目录

📋前言

在 C 语言内存操作中,memcpy 和 memmove 都是用于内存拷贝的函数,但很多初学者容易混淆二者的区别,甚至误用 memcpy 导致程序出现诡异 Bug。今天我们就重点拆解 memmove 函数 ,搞懂它的用法、原理、与 memcpy 的核心区别,让你在开发中彻底避开内存拷贝的坑。


一、memmove函数是什么?

memmove 是 C 标准库 <string.h> 中提供的内存拷贝函数 ,全称是 memory move(内存移动),作用是将一段内存的数据拷贝到另一段内存中。

它的核心优势:支持内存区域重叠 的安全拷贝,这是 memcpy 做不到的。


二、函数原型与参数解析

1.1 头文件

使用前必须包含:

c 复制代码
#include <string.h>

1.2 函数原型

c 复制代码
void *memmove(void *dest, const void *src, size_t n);

1.3 参数说明

参数 含义
dest 目标内存地址(拷贝数据的目的地)
src 源内存地址(要拷贝的原始数据)
n 要拷贝的字节数(无符号整数)

1.4 返回值

返回目标内存的起始地址dest。


三、memmove的核心用法

memmove 的使用场景和 memcpy 几乎一致,唯一的区别是:当源内存和目标内存存在重叠时,必须用 memmove。

基础示例:普通内存拷贝

c 复制代码
#include <stdio.h>
#include <string.h>

int main()
{
    char src[] = "Hello, memmove!";
    char dest[50] = { 0 };  // 初始化目标数组

    // 拷贝 src 中的所有数据(包含结束符)
    memmove(dest, src, strlen(src) + 1);

    printf("源字符串:%s\n", src);
    printf("目标字符串:%s\n", dest);
    return 0;
}

输出结果:

复制代码
源字符串:Hello, memmove!
目标字符串:Hello, memmove!

这个例子中内存不重叠,memmove 和 memcpy 效果完全相同。


四、关键:memmove与memcpy的区别

这是面试和开发中最常考、最容易踩坑的点,必须吃透!

4.1 核心区别

  • memcpy :不检查内存重叠 ,直接从前往后拷贝,重叠时会导致数据覆盖、结果错误。
  • memmove :会处理内存重叠 ,根据内存地址自动选择拷贝方向,拷贝结果永远安全。

4.2 什么是内存重叠?

举个直观的例子:

有一个数组 arr[10] = {1,2,3,4,5,6,7,8,9,10},我们想把前5个元素(1-5) 拷贝到 从第3个位置开始 的区域:

此时源内存和目标内存部分重叠 ,用 memcpy 会出错,用 memmove 则安全。

4.3 实战对比:重叠内存拷贝

c 复制代码
#include <stdio.h>
#include <string.h>

int main()
{
    int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
    int len = sizeof(arr) / sizeof(arr[0]);

    // 场景:把 arr[0]~arr[4] 拷贝到 arr[2]~arr[6](内存重叠)
    // 用 memcpy(错误示例)
    // memcpy(arr+2, arr, 5*sizeof(int));

    // 用 memmove(正确示例)
    memmove(arr + 2, arr, 5 * sizeof(int));

    // 打印结果
    for (int i = 0; i < len; i++)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}

memmove 正确输出:

复制代码
1 2 1 2 3 4 5 8 9 10

memcpy 错误输出:

复制代码
1 2 1 2 1 2 1 8 9 10

原因:memcpy 从前往后拷贝,刚拷贝的新数据覆盖了源数据,导致后续拷贝拿到的是错误值。


五、memmove底层实现原理

为什么 memmove 能处理重叠内存?核心是拷贝方向判断:

  1. 比较 dest 和 src 的地址大小;
  2. 如果 dest 在 src 前方 → 从前往后拷贝;
  3. 如果 dest 在 src 后方 → 从后往前拷贝;

这样就能避免重叠区域的数据被提前覆盖。

手写简易版 memmove(理解原理):

c 复制代码
#include <stdio.h>

// 自定义 memmove 函数
void* my_memmove(void* dest, const void* src, size_t n)
{
    // 转换成 char 指针,以便按字节操作
    unsigned char* d = (unsigned char*)dest;
    const unsigned char* s = (const unsigned char*)src;

    // 判断是否有重叠,以及 dest 是否在 src 之后
    if (d > s && d < s + n)
    {
        // 情况 B:重叠且 dest 在 src 右侧
        // 必须从后往前复制
        for (size_t i = n; i > 0; i--)
        {
            d[i - 1] = s[i - 1];
        }
    }
    else
    {
        // 情况 A:无重叠 或 dest 在 src 左侧
        // 从前往后复制
        for (size_t i = 0; i < n; i++)
        {
            d[i] = s[i];
        }
    }
    return dest;
}

// 测试代码
int main()
{
    char str[] = "Hello, World!";

    // 将 "World" 移动到 "Hello" 的位置(重叠移动)
    my_memmove(str, str + 7, 5); // 移动 "World"
    printf("%s\n", str); // 输出 "World, World!"


    int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    my_memmove(arr + 4, arr + 2, 4 * sizeof(int));

    for (int i = 0; i < 8; i++)
    {
        printf("%d ", arr[i]);
    }
    // 输出: 1 2 3 4 3 4 5 6

    return 0;
}

这个简易实现完美还原了 memmove 的核心逻辑,看懂它就彻底理解了函数原理。


六、使用memmove的注意事项

  1. 必须保证目标内存空间足够

    目标内存 dest 必须有至少 n 字节的可用空间,否则会造成内存越界,导致程序崩溃。

  2. 参数 n 是字节数,不是元素个数

    拷贝数组时,要计算总字节数:元素个数 × 单个元素大小,例如:

    c 复制代码
    // 拷贝5个int类型数据
    memmove(dest, src, 5 * sizeof(int));
  3. src 用 const 修饰

    标准库中 src 是 const 指针,保证源数据不会被修改,这是安全编程的规范。

  4. 优先使用 memmove

    除非你能100%确定内存不重叠,否则日常开发中直接用 memmove 替代 memcpy,避免潜在的重叠风险。


📝全文总结

  1. memmove 是 <string.h> 中的安全内存拷贝函数,支持内存重叠场景;
  2. 函数原型:void *memmove(void *dest, const void *src, size_t n);;
  3. 与 memcpy 核心区别:memmove 处理重叠内存,memcpy 不处理;
  4. 底层原理:根据地址大小自动选择从前往后 或从后往前拷贝;
  5. 开发建议:不确定内存是否重叠时,优先使用 memmove,更安全。

掌握 memmove,就能彻底解决 C 语言中内存拷贝的重叠问题,写出更健壮的代码。如果觉得本文对你有帮助,欢迎点赞收藏~

相关推荐
en.en..1 分钟前
C语言---宏
c语言·开发语言
郝学胜-神的一滴10 分钟前
C++ Templates 01:拨开迷雾,读懂C++模板经典著作
开发语言·c++·程序人生·游戏·游戏引擎·软件构建
言乐630 分钟前
Python实现关税自动计算模型
开发语言·python·django·virtualenv·pygame
朝朝辞暮i30 分钟前
C++ 第 14 课:引用 &
开发语言·c++·算法
白山编程大哥41 分钟前
适合初学者练习的 C/C++ 开源项目推荐
c语言·c++·开源
梅雅达编程笔记1 小时前
04-Python CSV数据保存与翻页抓取
开发语言·爬虫·python·pandas·数据采集·csv
小灰灰搞电子1 小时前
C 语言 <stdlib.h> 头文件详解
c语言·stdlib.h
C++ 老炮儿的技术栈1 小时前
有符号变量与无符号变量的区别
服务器·开发语言·前端·数据结构·c++·算法·c
估值探索者1 小时前
【Python量化策略实战 #04】Donchian 通道假突破太多?用 ATR 阈值过滤跑通真实突破信号
开发语言·python·接口·api接口·数据api接口·股票数据api接口
个 人 练 习 生1 小时前
C++:模板初阶详解
开发语言·c++·经验分享·学习