
🌈个人主页:聆风吟_
🔥系列专栏:C语言标准库
🔖少年有梦不应止于心动,更要付诸行动。
文章目录
- 📋前言
- 一、memmove函数是什么?
-
- 二、函数原型与参数解析
- [1.1 头文件](#1.1 头文件)
- [1.2 函数原型](#1.2 函数原型)
- [1.3 参数说明](#1.3 参数说明)
- [1.4 返回值](#1.4 返回值)
- 三、memmove的核心用法
- 四、关键:memmove与memcpy的区别
-
- [4.1 核心区别](#4.1 核心区别)
- [4.2 什么是内存重叠?](#4.2 什么是内存重叠?)
- [4.3 实战对比:重叠内存拷贝](#4.3 实战对比:重叠内存拷贝)
- 五、memmove底层实现原理
- 六、使用memmove的注意事项
- 📝全文总结
📋前言
在 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 能处理重叠内存?核心是拷贝方向判断:
- 比较
dest和src的地址大小; - 如果
dest在src前方 → 从前往后拷贝; - 如果
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的注意事项
-
必须保证目标内存空间足够
目标内存
dest必须有至少n字节的可用空间,否则会造成内存越界,导致程序崩溃。 -
参数
n是字节数,不是元素个数拷贝数组时,要计算总字节数:
元素个数 × 单个元素大小,例如:c// 拷贝5个int类型数据 memmove(dest, src, 5 * sizeof(int)); -
src用const修饰标准库中
src是const指针,保证源数据不会被修改,这是安全编程的规范。 -
优先使用
memmove除非你能100%确定内存不重叠,否则日常开发中直接用
memmove替代memcpy,避免潜在的重叠风险。
📝全文总结
memmove是<string.h>中的安全内存拷贝函数,支持内存重叠场景;- 函数原型:
void *memmove(void *dest, const void *src, size_t n);; - 与
memcpy核心区别:memmove处理重叠内存,memcpy不处理; - 底层原理:根据地址大小自动选择从前往后 或从后往前拷贝;
- 开发建议:不确定内存是否重叠时,优先使用
memmove,更安全。
掌握 memmove,就能彻底解决 C 语言中内存拷贝的重叠问题,写出更健壮的代码。如果觉得本文对你有帮助,欢迎点赞收藏~