在 C 语言的编程世界里,我们经常需要和内存打交道。如果你需要把一块内存里的数据“原封不动”地搬运到另一块内存中,那么标准库提供的 memcpy 函数绝对是你的得力助手。

今天我们就来掰开揉碎地讲讲这个函数,看看它怎么用,以及有哪些需要避开的坑。

1. 认识 memcpy:它是做什么的?

memcpy 的全称是 memory copy(内存拷贝)。它的核心功能非常简单直接:从源内存地址的起始位置开始,拷贝 n 个字节的数据到目标内存地址中。

不管你内存里存的是字符串、整型数组还是复杂的结构体,在 memcpy 眼里,它们都只是一串毫无感情的二进制字节流。它只负责搬运,绝不夹带私货。

2. 函数原型与参数解析

要使用 memcpy,首先需要引入头文件:

#include <string.h>

它的函数原型长这样:

void *memcpy(void *dest, const void *src, size_t n);

我们来逐一拆解这些参数:

  • dest (Destination):目标指针。指向你想要把数据存放进去的那块内存。

  • src (Source):源指针。指向你想要读取数据的哪块内存。注意前面有个 const,说明它不会修改源数据。

  • n:你要拷贝的字节数(注意,是字节数,不是元素个数!这是新手常犯的错误)。

  • 返回值:函数会返回一个指向目标内存区域 dest 的指针。

3. 代码实战:memcpy 怎么用?

光说不练假把式,我们来看看实际代码中怎么用。

场景一:拷贝字符串

虽然拷贝字符串通常用 strcpy,但 memcpy 同样可以胜任,只要你指定好长度即可。

#include <stdio.h>
#include <string.h>

int main() {
    const char src[50] = "Hello, C Programming!";
    char dest[50];

    // 把 src 中的字符串(包含末尾的 '\0')拷贝到 dest 中
    // +1 是为了把隐藏的字符串结束符 '\0' 也拷过去
    memcpy(dest, src, strlen(src) + 1);

    printf("目标字符串 dest = %s\n", dest);
    return 0;
}

场景二:拷贝整型数组(重点)

这是 memcpy 最大显身手的地方。当你需要复制一个非字符数组时,strcpy 就无能为力了。

#include <stdio.h>
#include <string.h>

int main() {
    int src_array[] = {10, 20, 30, 40, 50};
    int dest_array[5];

    // 注意第三个参数:必须是 (元素个数 * 单个元素所占的字节数)
    memcpy(dest_array, src_array, 5 * sizeof(int));

    printf("拷贝后的 dest_array: ");
    for(int i = 0; i < 5; i++) {
        printf("%d ", dest_array[i]);
    }
    printf("\n");
    
    return 0;
}

4. 🚨 避坑指南:致命的“内存重叠”

memcpy 虽然高效,但它是个“愣头青”——它在拷贝时,不会检查源内存和目标内存是否发生重叠(Overlap)。

什么是内存重叠?假设你有一个数组,你想把前 5 个元素拷贝到从第 3 个元素开始的位置上。这时候源区域和目标区域就重叠了。如果你在这种情况下使用 memcpy,它的行为是未定义的(Undefined Behavior)。可能会导致数据在被读取前就被覆盖,拷出一堆乱码。

终极建议:

  • 如果你明确知道源内存和目标内存绝不可能重叠,放心大胆地使用 memcpy,它的效率非常高。

  • 如果你怀疑两块内存有可能重叠,请乖乖换成它的兄弟函数:memmove()memmove 会在拷贝前处理好重叠问题,保证数据安全,代价是稍微牺牲一点点性能。

总结

  • memcpy 用于拷贝任意类型的数据。

  • 按**字节(byte)**进行拷贝,计算长度时别忘了乘上 sizeof(数据类型)

  • 需要包含 <string.h>

  • 严禁用于有内存重叠的场景,重叠场景请找 memmove

C 库函数 – memcpy() | 菜鸟教程

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐