

前言
在C语言编程中,内存操作是绕不开的核心环节,而memcpy、memmove、memset、memcmp这几个内存函数更是高频使用的工具。它们直接作用于内存字节,不受数据类型限制,灵活度极高,但也因细节繁多容易踩坑。本文将从使用方法、核心特点、模拟实现三个维度,把这四个函数讲透,帮你彻底掌握内存操作的精髓。
一、memcpy
1. 函数核心说明
memcpy的核心作用是从源内存地址开始,向后复制指定字节数的数据到目标内存地址,函数原型如下:
c
void * memcpy ( void * destination, const void * source, size_t num );
- 关键特点 :
- 不识别
'\0':即便拷贝过程中遇到字符串结束符,也会继续拷贝,直到完成num个字节。 - 不处理重叠内存:若源地址(source)和目标地址(destination)的内存区域重叠,拷贝结果未定义,这是它和
memmove的核心区别。
- 不识别
2. 实用示例
比如将数组arr1的前5个int元素(共20字节)拷贝到arr2中:
c
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
// 拷贝20字节(5个int,每个int占4字节)
memcpy(arr2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
// 输出:1 2 3 4 5 0 0 0 0 0
printf("%d ", arr2[i]);
}
return 0;
}
3. 模拟实现
模拟实现的核心思路是按字节拷贝(因为要适配所有数据类型),同时校验指针合法性:
c
#include <assert.h>
void * memcpy ( void * dst, const void * src, size_t count)
{
// 断言防止空指针
assert(dst && src);
void * ret = dst;
// 按字节逐个拷贝
while (count--) {
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
// 返回目标地址,支持链式调用
return ret;
}
二、memmove
1. 函数核心说明
memmove是memcpy的增强版,原型和memcpy一致,但支持源/目标内存重叠的场景:
c
void * memmove ( void * destination, const void * source, size_t num );
当源内存和目标内存重叠时,必须使用memmove,否则会出现数据覆盖错误。
2. 实用示例
将数组arr1的前5个元素拷贝到从arr1+2开始的位置(内存重叠):
c
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
// 拷贝20字节到arr1+2的位置,内存重叠
memmove(arr1+2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
// 输出:1 2 1 2 3 4 5 8 9 10
printf("%d ", arr1[i]);
}
return 0;
}
3. 模拟实现
核心逻辑是分两种情况处理内存重叠:
- 若目标地址 ≤ 源地址,或目标地址 ≥ 源地址+拷贝字节数(无重叠):从低地址到高地址拷贝(和memcpy一致)。
- 若内存重叠:从高地址到低地址拷贝,避免数据覆盖。
c
#include <assert.h>
void * memmove ( void * dst, const void * src, size_t count)
{
assert(dst && src);
void * ret = dst;
// 情况1:无重叠,低地址→高地址拷贝
if (dst <= src || (char *)dst >= ((char *)src + count)) {
while (count--) {
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
}
// 情况2:有重叠,高地址→低地址拷贝
else {
dst = (char *)dst + count - 1;
src = (char *)src + count - 1;
while (count--) {
*(char *)dst = *(char *)src;
dst = (char *)dst - 1;
src = (char *)src - 1;
}
}
return ret;
}
三、memset
1. 函数核心说明
memset用于将指定内存区域的每个字节设置为指定值,原型如下:
c
void * memset ( void * ptr, int value, size_t num );
- 注意:
memset按字节赋值,因此仅适合单字节数据(如char)或批量设置0/0xff等场景,不能直接用于int数组赋值(除非赋值0)。
2. 实用示例
将字符串前6个字节设置为字符'x':
c
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "hello world";
// 将前6个字节设为'x'
memset (str,'x',6);
// 输出:xxxxxxworld
printf(str);
return 0;
}
四、memcmp
1. 函数核心说明
memcmp用于比较两个内存区域的前num个字节,原型如下:
c
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
返回值规则(按无符号字符比较):
| 返回值 | 含义 |
|---|---|
| < 0 | ptr1首个不同字节 < ptr2对应字节 |
| = 0 | 前num个字节完全相同 |
| > 0 | ptr1首个不同字节 > ptr2对应字节 |
2. 实用示例
比较两个字符数组的全部字节内容:
c
#include <stdio.h>
#include <string.h>
int main()
{
char buffer1[] = "DWgaOtP12df0";
char buffer2[] = "DWGAOTP12DF0";
int n;
// 比较整个数组的字节内容
n = memcmp(buffer1, buffer2, sizeof(buffer1));
if (n > 0)
printf("'%s' is greater than '%s'.\n", buffer1, buffer2);
else if (n < 0)
printf("'%s' is less than '%s'.\n", buffer1, buffer2);
else
printf("'%s' is the same as '%s'.\n", buffer1, buffer2);
// 输出:'DWgaOtP12df0' is greater than 'DWGAOTP12DF0'(小写字母ASCII码更大)
return 0;
}
总结
C语言的这四个内存函数各有侧重:
memcpy:基础内存拷贝,不处理重叠;memmove:增强版拷贝,支持内存重叠;memset:按字节设置内存值,注意赋值粒度;memcmp:按字节比较内存,区分无符号字符大小。
掌握它们的使用场景和底层实现逻辑,既能避免内存操作的坑,也能更深刻理解C语言"直面内存"的特性。实际开发中,优先使用库函数(效率更高、经过严格测试),理解模拟实现则能帮你夯实内存操作的基础。
至此,我们已梳理完"字符函数和字符串函数"的全部内容了。最后我们在文末来进行一个投个票,告诉我你对哪部分内容最感兴趣、收获最大,也欢迎在评论区聊聊你的学习感受。
以上就是本期博客的全部内容了,感谢各位的阅读以及关注。如有内容存在疏漏或不足之处,恳请各位技术大佬不吝赐教、多多指正。

