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
有什么区别?
