> 技术文档 > C语言 - 详解 memset 和 memcpy 的使用与区别

C语言 - 详解 memset 和 memcpy 的使用与区别


【C语言基础】详解 memset 和 memcpy 的使用与区别

在 C 语言开发过程中,操作内存是非常常见的需求。标准库中提供了两个高效处理内存的函数:memsetmemcpy。这两个函数虽然名称相似,但功能和应用场景完全不同。本文将对这两个函数的用法、参数含义、使用示例和常见误区进行系统性说明。

一、memset:用于初始化内存

函数原型

void *memset(void *s, int c, size_t n);

参数说明

  • s:指向要被设置的内存起始地址;
  • c:设置的值,只使用该值的低 8 位;
  • n:要设置的字节数。

基本用途

memset 通常用于将数组或结构体的内存设置为固定值,常见的是设置为 0。

示例 1:将数组清零

int arr[10];memset(arr, 0, sizeof(arr));

这段代码会将 arr 中的所有字节设置为 0,相当于把每个元素都初始化为 0。

示例 2:将缓存区填充为特定字符

char buffer[16];memset(buffer, \'A\', sizeof(buffer));

buffer 中的所有字节设置为字符 \'A\',即十六进制值 0x41。

二、memcpy:用于内存拷贝

函数原型

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

参数说明

  • dest:目标内存地址;
  • src:源内存地址;
  • n:要复制的字节数。

基本用途

memcpy 用于将一段内存中的内容复制到另一段内存,适用于复制数组、结构体或任意内存块。

例 1:复制数组内容

int a[5] = {1, 2, 3, 4, 5};int b[5];memcpy(b, a, sizeof(a));

将数组 a 的内容复制到数组 b 中。

例 2:复制字符串内容

char src[] = \"hello\";char dest[10];memcpy(dest, src, strlen(src) + 1); // 包括结尾的 \'\\0\'

将字符串 src 包含末尾的结束符完整复制到 dest 中。

三、功能对比

函数 功能 是否逐字节操作 应用场景 memset 将内存设置为某一字节 是 初始化、清空 memcpy 从一块内存复制到另一块 是 拷贝数组、结构体数据

四、注意

1. memset 设置非零整数数组时的错误用法

int arr[4];memset(arr, 1, sizeof(arr)); // 错误

该代码并不会将每个元素设置为整数 1,而是将每个字节设置为 0x01,结果可能是每个整数变成 0x01010101,即 16843009。这种写法容易造成逻辑错误。

建议:

如需将整数数组每个元素设置为 1,应使用循环赋值:

for (int i = 0; i < 4; i++) { arr[i] = 1;}

2. memcpy 不会自动添加字符串结束符

在复制字符串时,若不手动包含 \'\\0\',目标内存可能不是合法字符串。

char src[] = \"abc\";char dst[10];memcpy(dst, src, 3); // 未复制 \'\\0\',dst 不是完整字符串

应写为:

memcpy(dst, src, strlen(src) + 1);

五、应用场景

1. 结构体初始化

struct Config { int id; char name[32]; float value;};struct Config cfg;memset(&cfg, 0, sizeof(cfg));

此操作将结构体所有字段初始化为 0,避免出现未定义值。

2. 缓存区清空

char rx_buffer[64];memset(rx_buffer, 0, sizeof(rx_buffer));

用于网络、串口、文件读取前,清空接收缓存区,防止数据残留。

3. 拷贝数据结构

struct Data a = {1, \"sensor\", 3.14};struct Data b;memcpy(&b, &a, sizeof(struct Data));

快速复制结构体的所有内容,适用于数据缓存、消息转发等场景。

六、总结

memsetmemcpy 是 C 语言中最基本、最常用的两个内存操作函数:

  • memset 用于将一段内存设置为统一的字节值,适合初始化或清空。
  • memcpy 用于将一段内存的内容复制到另一段地址,适合数据备份或传输。

正确理解参数含义和工作原理,能够避免常见错误并提升代码的健壮性和效率。在实际开发中,这两个函数经常配合使用,是处理底层数据结构时的重要工具。

如需配合调试观察效果,可通过 GDB 或在代码中加入打印函数,查看内存填充或拷贝前后的变化,以加深理解。


(完)