首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >收集飞花令碎片——C语言内存函数

收集飞花令碎片——C语言内存函数

作者头像
枫亭湖区
发布2025-11-13 09:16:12
发布2025-11-13 09:16:12
880
举报

“山在雾中若隐若现,水在光里缓缓流淌。 我撑一叶小舟,不问归期, 只想听这天地的一声叹息。”

C语言 中,所谓的内存函数(Memory Functions),是指用于直接操作内存内容的一组标准库函数,主要定义在头文件:

代码语言:javascript
复制
#include <string.h>

👉这些函数通常以mem开头,主要作用是: 👉在内存中复制、比较、设置或移动一段字节数据 👉它们操作的单位是字节(byte),而不是字符或字符串

各函数详解
  • 1️⃣ memcpy(void *dest, const void *src, size_t n)
  • 2️⃣ memmove(void *dest, const void *src, size_t n)
  • 3️⃣ memset(void *ptr, int value, size_t n)
  • 4️⃣ memcmp(const void *a, const void *b, size_t n)
  • 5️⃣ memchr(const void *ptr, int value, size_t n)
  • 两内存函数的模拟实现
    • memcpy
      • 为何memcpy不处理内存重叠情况
    • memmove
  • 如果你觉得对你有帮助
  • 请给我一个三连哦谢谢啦

1️⃣ memcpy(void *dest, const void *src, size_t n)

  • 作用: 从源内存区域复制n个字节到目标区域。
  • 注意: 源和目标区域不能重叠!
代码语言:javascript
复制
char src[] = "Hello";
char dest[10];
memcpy(dest, src, 6);   // 复制包括'\0'在内的6个字节
printf("%s\n", dest);   // 输出 Hello

空间卷轴:memcpy函数


2️⃣ memmove(void *dest, const void *src, size_t n)

  • 作用: 与 memcpy 类似,但支持重叠区域。
代码语言:javascript
复制
char data[] = "12345";
memmove(data + 2, data, 3);   // 支持重叠
printf("%s\n", data);         // 输出 12123

空间卷轴:memmove函数


3️⃣ memset(void *ptr, int value, size_t n)

  • 作用: 将从 ptr 开始的 n 个字节都设为 value(按字节存)。
代码语言:javascript
复制
char buf[10];
memset(buf, 'A', 5);
buf[5] = '\0';
printf("%s\n", buf); // 输出 AAAAA

www空间卷轴:memset


4️⃣ memcmp(const void *a, const void *b, size_t n)

  • 作用: 比较两块内存前 n 个字节。
  • 返回值:
    • < 0 :a < b
    • = 0 :a == b
    • > 0 :a > b
代码语言:javascript
复制
char a[] = "abc";
char b[] = "abd";
int result = memcmp(a, b, 3);
printf("%d\n", result);  // 输出负数

空间卷轴:memcmp函数


5️⃣ memchr(const void *ptr, int value, size_t n)

  • 作用: 在内存中查找值为 value 的字节,返回首次出现位置的指针。
代码语言:javascript
复制
char str[] = "OpenAI";
char *p = memchr(str, 'A', 6);
if (p)
    printf("Found at: %s\n", p); // 输出 AI

空间卷轴:memchr函数


两内存函数的模拟实现

memcpy

代码语言:javascript
复制
/**
 * 内存复制函数
 * 将指定字节数的数据从源内存地址复制到目标内存地址
 * 
 * @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不处理内存重叠情况
代码语言:javascript
复制
memcpy(data + 2, data, 5);
// 源: data[0] 开始的5个字节 "abcde"
// 目标: data[2] 开始的5个字节
代码语言:javascript
复制
初始: 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"
  • 关键问题: 第3步:data[4] = data[2],但此时 data[2] 已经被改为 a(不是原来的 c) 源数据在复制过程中被修改了!
代码语言:javascript
复制
// 循环展开 - 逐字节复制
*(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"

memmove

代码语言:javascript
复制
/**
 * 安全的内存移动函数
 * 处理内存重叠情况,保证复制结果的正确性
 * 
 * @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;
}

如果你觉得对你有帮助

请给我一个三连哦谢谢啦

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-11-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 各函数详解
  • 1️⃣ memcpy(void *dest, const void *src, size_t n)
  • 2️⃣ memmove(void *dest, const void *src, size_t n)
  • 3️⃣ memset(void *ptr, int value, size_t n)
  • 4️⃣ memcmp(const void *a, const void *b, size_t n)
  • 5️⃣ memchr(const void *ptr, int value, size_t n)
  • 两内存函数的模拟实现
    • memcpy
      • 为何memcpy不处理内存重叠情况
    • memmove
  • 如果你觉得对你有帮助
  • 请给我一个三连哦谢谢啦
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档