memset 是 C 標準庫 <string.h> 中最高效的內存填充函數,廣泛用於結構體/數組初始化、緩衝區清零。本文詳細講解其原型、語義、常見誤區及替代方案。
void *memset(void *ptr, int value, size_t num);
ptr:目標內存起始地址;value:填充字節值(**以 unsigned char 形式填充**,即取 value & 0xFF);num:填充字節數;ptr,便於鏈式調用。將
ptr指向的連續num個字節,**逐字節** 設置為value的低 8 位。
這意味著:
0xFF(即 -1)常用於將有符號整數數組初始化為 -1。// 1. 結構體/數組清零(最推薦)
struct Student { int id; char name[20]; double score; } stu;
memset(&stu, 0, sizeof(stu));
// 2. 字符數組初始化
char buf[100];
memset(buf, '*', sizeof(buf)); // 填充 '*'
buf[sizeof(buf)-1] = '\0'; // 手動加終止符
// 3. 整型數組置 -1(每字節 0xFF)
int arr[10];
memset(arr, 0xFF, sizeof(arr)); // 每個 int 變為 0xFFFFFFFF = -1
| 錯誤場景 | 代碼示例 | 後果 | 正確做法 |
|---|---|---|---|
| 嘗試將 int 數組置為 1 | memset(arr, 1, sizeof(arr)) | 每字節變 0x01,int 值變 0x01010101 (16843009) | 用循環賦值或 std::fill (C++) |
| 填充指針數組為 NULL | memset(ptr_arr, 0, ...) | **僅在 NULL 為全 0 位模式的平台上安全**(絕大多數平台成立,但標準不保證) | 循環賦 NULL 或 calloc |
| 填充 float/double 為 0.0 | memset(farr, 0, ...) | IEEE 754 下 0.0 位模式全 0,**碰巧安全**,但不可移植 | 循環賦 0.0 或靜態初始化 |
| size_t 參數傳錯 | memset(buf, 0, sizeof(ptr)) | 只清零指針大小(4/8 字節),非緩衝區大小 | sizeof(buf) 或已知長度 |
| 函數 | 用途 | 終止條件 | 適用類型 |
|---|---|---|---|
memset | 內存填充 | 字節計數 | 任意類型(按字節) |
memcpy | 內存拷貝 | 字節計數 | 任意類型(含結構體、數組) |
strcpy | 字符串拷貝 | 遇到 \0 | 僅字符串(需保證目標足夠大) |
關鍵區別:memcpy 可拷貝含 \0 的二進制數據;strcpy 遇 \0 停止,**不檢查目標緩衝區大小**,極易溢出。
memset(ptr, 0, size) 是公認最高效、可移植的清零方式;struct S s = {0}; 或 {.a=1} 更清晰、類型安全;std::fill、std::fill_n、value-initialization ( T t = T(); 或 new T() );explicit_bzero (BSD) 或 memset_s (C11 Annex K) 或 volatile 指針技巧。memset 是「字節級填充」利器,**清零是本職工作**,其他數值填充需極度謹慎。理解其「按字節、無類型感知」的本質,才能避開隱蔽 Bug,寫出健壯的系統級代碼。