“山在雾中若隐若现,水在光里缓缓流淌。 我撑一叶小舟,不问归期, 只想听这天地的一声叹息。”
在 C语言 中,所谓的内存函数(Memory Functions),是指用于直接操作内存内容的一组标准库函数,主要定义在头文件:
#include <string.h>👉这些函数通常以mem开头,主要作用是:
👉在内存中复制、比较、设置或移动一段字节数据
👉它们操作的单位是字节(byte),而不是字符或字符串
n个字节到目标区域。char src[] = "Hello";
char dest[10];
memcpy(dest, src, 6); // 复制包括'\0'在内的6个字节
printf("%s\n", dest); // 输出 Hellochar data[] = "12345";
memmove(data + 2, data, 3); // 支持重叠
printf("%s\n", data); // 输出 12123char buf[10];
memset(buf, 'A', 5);
buf[5] = '\0';
printf("%s\n", buf); // 输出 AAAAAwww空间卷轴:memset
< 0 :a < b= 0 :a == b> 0 :a > bchar a[] = "abc";
char b[] = "abd";
int result = memcmp(a, b, 3);
printf("%d\n", result); // 输出负数char str[] = "OpenAI";
char *p = memchr(str, 'A', 6);
if (p)
printf("Found at: %s\n", p); // 输出 AI/**
* 内存复制函数
* 将指定字节数的数据从源内存地址复制到目标内存地址
*
* @param dst 目标内存地址(复制目的地)
* @param src 源内存地址(复制来源)
* @param count 要复制的字节数
* @return 返回目标内存地址的原指针
*/
void *memcpy(void *dst, const void *src, size_t count)
{
// 保存原始目标指针,用于函数返回
void *ret = dst;
// 参数有效性检查:确保目标地址和源地址都不为空
assert(dst != NULL);
assert(src != NULL);
/*
* 从低地址到高地址逐字节复制
* 注意:此实现不处理内存重叠情况
*/
while (count--) {
// 逐字节复制:将源地址的一个字节复制到目标地址
*(char *)dst = *(char *)src;
// 移动目标指针到下一个字节位置
dst = (char *)dst + 1;
// 移动源指针到下一个字节位置
src = (char *)src + 1;
}
// 返回原始的目标指针(标准memcpy函数的约定)
return ret;
}memcpy(data + 2, data, 5);
// 源: data[0] 开始的5个字节 "abcde"
// 目标: data[2] 开始的5个字节初始: a b c d e f g h i \0
步骤: a b a d e f g h i \0 (复制data[0]到data[2])
a b a b e f g h i \0 (复制data[1]到data[3])
a b a b a f g h i \0 (复制data[2]到data[4])
a b a b a b g h i \0 (复制data[3]到data[5])
a b a b a b a h i \0 (复制data[4]到data[6])
结果: "abababa hi"data[4] = data[2],但此时 data[2] 已经被改为 a(不是原来的 c)
源数据在复制过程中被修改了!// 循环展开 - 逐字节复制
*(data+2) = *(data+0); // data[2] = 'a' → "abade fghi"
*(data+3) = *(data+1); // data[3] = 'b' → "ababe fghi"
*(data+4) = *(data+2); // data[4] = 'a' → "ababa fghi" ← 问题出现!
*(data+5) = *(data+3); // data[5] = 'b' → "abababghi"
*(data+6) = *(data+4); // data[6] = 'a' → "abababa hi"/**
* 安全的内存移动函数
* 处理内存重叠情况,保证复制结果的正确性
*
* @param dst 目标内存地址
* @param src 源内存地址
* @param count 要复制的字节数
* @return 返回目标内存地址
*/
void *memmove(void *dst, const void *src, size_t count)
{
// 保存原始目标指针用于返回
void *ret = dst;
// 检查是否不需要重叠处理的情况:
// 1. 目标地址 <= 源地址 (反向重叠或不重叠)
// 2. 目标地址 >= 源地址 + count (完全不重叠)
if (dst <= src || (char *)dst >= ((char *)src + count)) {
/*
* 非重叠缓冲区 或 反向重叠
* 从低地址到高地址复制(正向复制)
*
* 内存布局示例:
* 情况1: dst <= src (反向重叠)
* [dst...dst+count]
* [src...src+count]
*
* 情况2: dst >= src+count (不重叠)
* [src...src+count] [dst...dst+count]
*/
while (count--) {
// 逐字节复制:源数据 → 目标位置
*(char *)dst = *(char *)src;
// 指针向前移动一个字节
dst = (char *)dst + 1;
src = (char *)src + 1;
}
}
else {
/*
* 重叠缓冲区(正向重叠)
* 从高地址到低地址复制(反向复制)
*
* 内存布局示例:
* [src.........src+count]
* [dst.........dst+count]
*
* 必须反向复制以避免覆盖尚未复制的源数据
*/
// 将指针移动到各自内存块的末尾
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;
}