【C语言】从零实现 memcpy:原理、陷阱与实战

个人主页:BabyZZの秘密日记
收入专栏:C语言


文章目入

    • 1. 什么是 `memcpy`?
    • 2. 标准库版本示例
    • 3. 自己写一个 `my_memcpy`
      • 3.1 思路拆解
      • 3.2 完整实现
      • 3.3 测试代码
    • 4. 常见坑 & 面试追问
    • 5. 小结

本文面向 C 语言初学者与面试复习人群,通过两个完整示例带你深入理解 memcpy 的工作机制,并亲手实现一个“简化版”的 my_memcpy。阅读时间约 5 分钟。


1. 什么是 memcpy

memcpy 是 C 标准库 提供的高频内存拷贝函数,原型如下:

void *memcpy(void *dest, const void *src, size_t n);
  • dest:目标内存首地址
  • src:源内存首地址
  • n:要拷贝的字节数

特点

  • 字节 为单位逐位复制,不关注数据类型。
  • 不处理 内存重叠 场景(那是 memmove 的活)。
  • 返回 dest,方便链式调用。

2. 标准库版本示例

先看一段最简单、最安全的用法:

#include 
#include 

int main(void)
{
    int arr1[] = {1, 2, 3, 4, 5};
    int arr2[5] = {0};

    /* 拷贝 5 个 int 所占字节数 */
    memcpy(arr2, arr1, sizeof(arr1[0]) * 5);

    for (int i = 0; i < 5; ++i)
        printf("%d ", arr2[i]);   /* 1 2 3 4 5 */

    return 0;
}

运行结果:

1 2 3 4 5

3. 自己写一个 my_memcpy

3.1 思路拆解

  1. 逐字节拷贝
    任何类型的指针都可以强转为 char*,因为 char 大小始终为 1 字节。
  2. 空指针检查
    使用 assert 在调试阶段拦截空指针。
  3. 返回原始 dest
    遵循标准接口规范,方便链式调用。

3.2 完整实现

#include 
#include 

void *my_memcpy(void *dest, const void *src, size_t num)
{
    assert(dest && src);            /* 防御性编程 */
    unsigned char *d = dest;
    const unsigned char *s = src;

    while (num--)
        *d++ = *s++;

    return dest;
}

说明

  • 使用 unsigned char* 而非 char*,避免符号扩展问题。
  • 不处理重叠内存,保持与 memcpy 语义一致。

3.3 测试代码

int main(void)
{
    int arr1[] = {1, 2, 3, 4, 5};
    int arr2[5] = {0};

    my_memcpy(arr2, arr1, sizeof(arr1));

    for (int i = 0; i < 5; ++i)
        printf("%d ", arr2[i]);   /* 1 2 3 4 5 */

    return 0;
}

4. 常见坑 & 面试追问

问题 解答
为何以字节为单位? memcpy 不假设数据类型,按字节复制最通用。
能否拷贝结构体? 可以,但注意结构体对齐和潜在未定义填充字节。
重叠内存会怎样? 行为未定义,需改用 memmove
效率如何? 商用库通常使用 SIMD 指令优化,手写版本仅教学用。

5. 小结

  • 会用:记住 memcpy(dest, src, 字节数) 三要素。
  • 会写:逐字节循环 + 空指针检查。
  • 会避坑:重叠内存选 memmove,结构体注意对齐。

如果文章对你有帮助,记得点赞 & 在看!

你可能感兴趣的:(C语言,c语言,开发语言)