首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言 memset 函數深度解析:用法、陷阱與最佳實踐

     編輯:關於C語言

C語言 memset 函數深度解析:用法、陷阱與最佳實踐

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 位。

這意味著:

  • **只能按字節填充**,不能直接設置 int/float 等多字節類型的具體數值(除非該數值每字節相同,如 0 或 -1/0xFF);
  • **清零(置 0)是最安全、最常用的場景**;
  • 填充 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 數組置為 1memset(arr, 1, sizeof(arr))每字節變 0x01,int 值變 0x01010101 (16843009)用循環賦值或 std::fill (C++)
填充指針數組為 NULLmemset(ptr_arr, 0, ...)**僅在 NULL 為全 0 位模式的平台上安全**(絕大多數平台成立,但標準不保證)循環賦 NULL 或 calloc
填充 float/double 為 0.0memset(farr, 0, ...)IEEE 754 下 0.0 位模式全 0,**碰巧安全**,但不可移植循環賦 0.0 或靜態初始化
size_t 參數傳錯memset(buf, 0, sizeof(ptr))只清零指針大小(4/8 字節),非緩衝區大小sizeof(buf) 或已知長度

memset vs memcpy vs strcpy

函數用途終止條件適用類型
memset內存填充字節計數任意類型(按字節)
memcpy內存拷貝字節計數任意類型(含結構體、數組)
strcpy字符串拷貝遇到 \0僅字符串(需保證目標足夠大)

關鍵區別:memcpy 可拷貝含 \0 的二進制數據;strcpy 遇 \0 停止,**不檢查目標緩衝區大小**,極易溢出。

最佳實踐建議

  1. 優先用於清零:memset(ptr, 0, size) 是公認最高效、可移植的清零方式;
  2. 結構體初始化:C99 指定初始化器 struct S s = {0}; 或 {.a=1} 更清晰、類型安全;
  3. C++ 偏好:std::fill、std::fill_n、value-initialization ( T t = T(); 或 new T() );
  4. 安全性:針對敏感數據(密鑰、密碼)清零時,防止編譯器優化掉調用,使用 explicit_bzero (BSD) 或 memset_s (C11 Annex K) 或 volatile 指針技巧。

總結

memset 是「字節級填充」利器,**清零是本職工作**,其他數值填充需極度謹慎。理解其「按字節、無類型感知」的本質,才能避開隱蔽 Bug,寫出健壯的系統級代碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved