22、memcpy、memset
大约 4 分钟C语言基础程序程序厨
C语言中,除了malloc、realloc、calloc、free申请或释放内存,还有几个非常有用的函数来处理内存的拷贝和设置,其中 memcpy、memset 和 memmove 是最常用的几个。
本文会详细讲解这三个函数的用法、参数、返回值、适用场景和注意事项。
memcpy
memcpy 函数用于从源内存地址的起始位置开始拷贝 n 个字节到目标内存地址的起始位置。它不会处理重叠内存区域的情况,即源地址和目标地址不能有部分重叠,否则结果未定义。
参数与返回值
memcpy 的函数声明如下:
void* memcpy(void* dest, const void* src, size_t n);
dest:目标内存地址的指针,类型为void*。src:源内存地址的指针,类型为const void*。n:要拷贝的字节数,类型为size_t。
返回值是目标内存地址的指针,即 dest,一般用不到。
使用场景
memcpy 常用于需要大块内存数据复制的场景,如复制结构体、数组等类型的数据。例如:
struct MyStruct {
int a;
float b;
char c;
};
MyStruct src = {1, 2.3f, 'x'};
MyStruct dest;
memcpy(&dest, &src, sizeof(MyStruct));
注意事项
- 重叠内存区域:
memcpy不处理源和目标内存重叠的情况,如果重叠,需要使用memmove。 - 目标内存大小:必须确保目标内存区域足够大以容纳要拷贝的数据,否则可能会导致内存越界。
memcpy 和 memmove 的区别
memmove 与 memcpy 类似,但 memmove 能够正确处理源和目标内存重叠的情况。因此,在处理可能重叠的内存区域时,应使用 memmove****。
memset
用于将目标内存区域的前 n 个字节设置为指定的值(通常是一个字节的值,但会被扩展到整个内存区域)。
参数与返回值
memset 的函数声明如下:
void* memset(void* s, int c, size_t n);
s:目标内存地址的指针,类型为void*。c:要设置的值,虽然参数类型是int,但只使用其低字节(即一个字节的值)。n:要设置的字节数,类型为size_t。
返回值是目标内存地址的指针,即 s,一般用不到。
使用场景
memset 常用于初始化内存区域为特定值,主要就是将内存区域清零:
int arr[10];
memset(arr, 0, sizeof(arr)); // 将数组 arr 初始化为 0
注意事项
- 字节值:
memset设置的值是按字节设置的,如果目标类型是大于一个字节的(如int),则整个内存区域会以该字节值进行填充,可能不会得到预期的结果。
memmove
memmove 的用法与 memcpy 几乎相同,但能够正确处理内存重叠的情况。
参数与返回值
memmove 的函数声明如下:
void* memmove(void* dest, const void* src, size_t n);
dest:目标内存地址的指针。src:源内存地址的指针。n:要拷贝的字节数。
memmove 的返回值也是目标内存地址的指针,即 dest,通常用不到。
使用场景
通常用于需要处理源和目标内存可能重叠的拷贝任务。例如:
char str[] = "1234567890";
char* src = str + 3; // 指向 '4'
char* dest = str + 2; // 指向 '3',与 src 重叠
memmove(dest, src, 5); // 将 "45678" 拷贝到 "3" 之后的位置,得到 "124567890"
总结
memcpy:用于内存拷贝,不处理重叠区域,适用于大块数据拷贝。memset:用于内存初始化,按字节设置值,适用于初始化内存为特定值。memmove:用于内存拷贝,能处理重叠区域,是memcpy的安全版本。
在使用这些函数时,务必注意目标内存区域的大小和源内存区域的数据,避免内存越界和未定义行为。
练习
- 编写一个程序,定义两个整型数组
src和dest,其中src包含 5 个元素{1, 2, 3, 4, 5},使用memcpy将src数组的内容复制到dest数组中,并打印dest数组的内容。 - 编写一个程序,定义一个整型数组
arr,包含 10 个元素,使用memset将数组的所有元素初始化为 0,并打印数组的内容以验证。
进阶
- 调研
memcpy的实现原理 - 调研
memset的实现原理 - 调研
memmove的实现原理 memcpy和strcpy有什么区别?





