标准库中的memcpy函数(string.h)旨在逐字节复制内存区域,从一个地方到另一个地方。这是一个用于复制数组、结构体和其他数据块的通用工具,当性能至关重要且不需要类型转换时,使用该工具。
问题背景:
memcpy与标准库的第一版一起出现,当时需要处理“原始”内存块,例如,处理文件、网络数据包、数据序列化。类似的函数几乎在所有低级语言中都有。
问题:
memcpy仅对字节进行操作,它不关心数据类型、对齐或内存区域的重叠。指定大小或不正确的区域会导致内存损坏或出乎意料的结果。此外,在重叠区域上使用memcpy会导致未定义行为。
解决方案:
仅当您确定以下几点时使用memcpy:
memmove函数。代码示例:
#include <string.h> typedef struct { int id; float value; } Item; Item src = {42, 3.14f}; Item dest; memcpy(&dest, &src, sizeof(Item)); // 字节复制结构
关键特性:
可以使用memcpy复制字符串(char)吗?
可以,前提是确切知道长度。如果字符串是null-terminated,通常使用strcpy或strncpy。如果弄错大小,可能会导致越界或者丢失结束的零。
char src[] = "abc"; char dest[4]; memcpy(dest, src, 4); // 复制3个字符+ '\0'
在通过memcpy复制具有非标准对齐或指针的结构时会发生什么?
memcpy既不考虑语义,也不考虑内部指针。如果结构存储动态字段(例如,char *buf;),则只复制地址,而不复制地址所指向的内容。这会导致所谓的“浅拷贝”。
typedef struct { char *buf; } Wrapper; Wrapper src = {malloc(10)}; Wrapper dest; memcpy(&dest, &src, sizeof(Wrapper)); // 仅复制指针字段,而非内容
如果在memcpy中src和dest重叠,会发生什么?
标准未定义其行为,可能会导致数据丢失。对于重叠的拷贝,请使用memmove:
memmove(dest, src, size); // 确保正确拷贝
数组重叠:使用memcpy向右移动部分数组,src和dest部分重叠。
优点:
缺点:
使用memmove处理重叠区域,数据量已明确计算为源结构中的字节数。
优点:
缺点: