技术博客:C语言 memset 完全指南——你用对了吗?
2026/5/30 1:19:10 网站建设 项目流程

一、函数原型

#include <string.h> void *memset(void *s, int c, size_t n);
参数含义
s要操作的内存起始地址
c要设置的值(只取低8位,0-255)
n要设置的字节数

返回值s本身(方便链式调用)


二、最常用场景:清零

1. 清零数组

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

2. 清零结构体

typedef struct { int id; char name[20]; float score; } Student; Student stu; memset(&stu, 0, sizeof(Student));

3. 清零字符串缓冲区

char buffer[256]; memset(buffer, 0, sizeof(buffer));

三、填充非零值(仅限字节类型)

1. 填充字符数组 ✅

char str[100]; memset(str, 'A', 50); // 前50个字节填 'A' memset(str + 50, 'B', 50); // 后50个字节填 'B'

2. 填充整数数组 ❌ 错误示

int arr[10]; memset(arr, 1, sizeof(arr)); // 想全部设为1? // 实际结果:arr[0] = 0x01010101 = 16843009

原因memset按字节填充,int占4个字节,每个字节都变成0x01,组合起来就是0x01010101

3. 填充指针数组 ⚠️ 危险

char *ptrs[10]; memset(ptrs, 0, sizeof(ptrs)); // 清零指针 → NULL,安全 memset(ptrs, 1, sizeof(ptrs)); // 危险!得到无效地址

四、结构体内存对齐的影响

typedef struct { char c; // 1 字节 int x; // 4 字节(编译器会填充3个空字节) } Test; Test t; memset(&t, 0, sizeof(Test)); // 连填充字节一起清零,完全安全

memset是整个字节逐字节填充,对齐的填充字节也会被覆盖,但这是好事——防止垃圾数据。


五、= {0}vsmemset对比

场景= {0}memset
定义局部变量✅ 简洁可以但多余
全局变量✅ 默认就是0多余
变量已存在需重新清零❌ 不行✅ 必须
动态内存❌ 不行✅ 必须
部分清零❌ 不行✅ 必须
填充非零字符❌ 不行✅ 必须

示例:重新清零

int arr[100]; // 使用 arr... // 想全部清零 memset(arr, 0, sizeof(arr)); // 只能这样

示例:动态内存

int *p = malloc(100 * sizeof(int)); memset(p, 0, 100 * sizeof(int)); // 或用 calloc(100, sizeof(int)) 一步到位

示例:部分清零

struct Data { int header; char payload[256]; int crc; } d; // 只清零 payload memset(d.payload, 0, sizeof(d.payload));

六、实用技巧

技巧1:安全计算字节数

int arr[50]; memset(arr, 0, sizeof(arr)); // ✅ 推荐 memset(arr, 0, 50 * sizeof(int)); // ✅ 也可以 memset(arr, 0, 50); // ❌ 只清了50字节(应200字节)

技巧2:链式调用

char buf[256]; memset(buf, 0, sizeof(buf)); strcpy(buf, "hello"); // 分开写 // 链式(但不推荐,可读性差) strcpy((char*)memset(buf, 0, sizeof(buf)), "hello");

技巧3:配合memcpy

char dest[100]; char src[] = "world"; memset(dest, 0, sizeof(dest)); // 先清零 memcpy(dest, src, sizeof(src) - 1); // 再拷贝(-1 去掉src的'\0') // dest[5] 已经是 '\0',安全输出字符串

技巧4:复位环形缓冲区

#define BUF_SIZE 1024 char ring_buf[BUF_SIZE]; int write_idx = 0, read_idx = 0; void reset_buffer(void) { memset(ring_buf, 0, BUF_SIZE); write_idx = 0; read_idx = 0; }

七、常见错误速查

错误写法后果正确写法
memset(arr, 1, sizeof(arr))整数值变0x01010101用 for 循环
memset(arr, 0, 50)数组长100只清零一半memset(arr, 0, sizeof(arr))
memset(&arr, 0, sizeof(arr))&arr多余但合法memset(arr, 0, sizeof(arr))
memset(p, 0, sizeof(p))p 是指针只清4/8字节memset(p, 0, size)传真实大小

八、性能说明

// 现代编译器会将 memset 优化为极高效的指令 memset(arr, 0, 1000); // 可能变成 rep stosd(一次写4字节) // 手写循环反而更慢 for (int i = 0; i < 1000; i++) arr[i] = 0;

放心用memset,它比大多数手写循环快。


九、快速记忆卡片

你想做什么代码
清零数组memset(arr, 0, sizeof(arr))
清零结构体memset(&stu, 0, sizeof(stu))
清零字符串memset(str, 0, sizeof(str))
填充字符 Amemset(buf, 'A', 100)
填充整数 1❌ 不行,用 for 循环
部分清零memset(&obj.member, 0, sizeof(obj.member))
动态内存清零memset(ptr, 0, size)或直接用calloc

十、一句话总结

memset是按字节填充的万能清零工具,最适合清零整块内存(数组、结构体、缓冲区)。定义时能用= {0}就用,但变量已存在、动态内存、部分清零时只能靠memset

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询