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

C 語言動態記憶體管理完整指南:malloc/calloc/realloc/free 實戰與避坑

     編輯:關於C語言

四大核心函數 (``)

函數原型特性初始化
malloc`void *malloc(size_t size)`分配 `size` 位元組**不初始化** (垃圾值)
calloc`void *calloc(size_t nmemb, size_t size)`分配 `nmemb * size` 位元組**歸零初始化** (全 0 位元組)
realloc`void *realloc(void *ptr, size_t size)`調整 `ptr` 指向區塊大小擴展部分**不初始化**
free`void free(void *ptr)`釋放 `ptr` 指向區塊N/A

標準使用模式


#include 
#include 

// 1. 基本分配與釋放
int *p = malloc(sizeof(int) * 10);
if (!p) { perror("malloc failed"); return -1; } // 必須檢查 NULL

for (int i = 0; i < 10; i++) p[i] = i * i; // 像陣列一樣用

free(p); // 歸還記憶體
p = NULL; // 防止懸空指針二次釋放/誤用

// 2. calloc: 結構體/陣列歸零
struct Node { int id; char *name; } *nodes;
nodes = calloc(100, sizeof(struct Node)); // 100 個 Node 全 0 (id=0, name=NULL)
// 等價: malloc(100 * sizeof(...)) + memset(..., 0, ...)
// calloc 可能更快 (OS 可直接映射零頁)

free(nodes);

// 3. realloc: 動態擴容/縮容 (擴容策略: 指數增長 2x)
char *buffer = malloc(100);
size_t cap = 100, len = 0;
// ... 追加資料 ...
if (len + needed > cap) {
    cap *= 2; // 指數增長均攤 O(1)
    char *new_buf = realloc(buffer, cap);
    if (!new_buf) { /* 處理 OOM, buffer 仍有效 */ }
    buffer = new_buf; // 關鍵:realloc 可能移動記憶體,必須用返回值更新指針
}
// ... 使用 buffer ...
free(buffer);

realloc 關鍵行為細節

  1. 可能移動記憶體:原地址空間不足時,分配新塊、複製資料、釋放舊塊。**舊指針失效**,必須接收返回值。
  2. 縮容 (`size < 原大小`)**:通常原地截斷,保留前段資料,返回同一指針。
  3. 擴容 (`size > 原大小`)**:新增部分**未初始化** (垃圾值)。
  4. `ptr == NULL`**:等價 `malloc(size)`。
  5. `size == 0`**:實作定義 (通常等價 `free(ptr)` 並返回 `NULL` 或唯一非 NULL 指針)。**不可依賴行為**。

常見錯誤與最佳實踐

❌ 錯誤 1:未檢查返回值


int *p = malloc(100); // 可能返回 NULL
p[0] = 1; // 如果 NULL -> Segfault

✅ **永遠檢查**:`if (!p) handle_oom();`

❌ 錯誤 2:釋放後未置 NULL (懸空指針)


free(p);
p[0] = 1; // UB: Use After Free (UAF)
free(p);  // UB: Double Free

✅ **釋放即置空**:`free(p); p = NULL;`

❌ 錯誤 3:`realloc` 未保存返回值


realloc(p, 200); // 如果移動了,p 變懸空指針,新塊洩漏

✅ **臨時變數接收**:`void *tmp = realloc(p, 200); if (tmp) p = tmp; else handle_oom();`

❌ 錯誤 4:類型轉換錯誤 (C++ 混編)


// C: void* 隱式轉換任意指針,無需轉型 (轉型反而隱藏漏 include 警告)
int *p = malloc(sizeof(int) * 10); // C 標準寫法

// C++: 必須強轉
int *p = (int*)malloc(sizeof(int) * 10); // 或 static_cast
// 建議跨語言頭檔用宏統一

❌ 錯誤 5:結構體柔性陣列成員分配


struct Packet { size_t len; char data[]; }; // C99 柔性陣列
// 正確分配:
struct Packet *pkt = malloc(sizeof(struct Packet) + 100 * sizeof(char));
pkt->len = 100;
// 錯誤: malloc(sizeof(struct Packet)) -> data 無空間

進階主題

  • 對齊分配 (C11 `aligned_alloc`, POSIX `posix_memalign`):SIMD/硬體 DMA 需對齊記憶體。
  • 自定義分配器:記憶體池、Arena Allocator、Buddy System,減少系統調用、碎片、提升緩存局部性。
  • 檢測工具:Valgrind (Memcheck), AddressSanitizer (ASan `-fsanitize=address`), Dr. Memory。CI 必須集成。
  • 嵌入式無 OS:靜態記憶體池 `static uint8_t heap[HEAP_SIZE]` + 簡易 `malloc/free` 實現 (如 TLSF 算法)。

總結口訣

  1. 分配必檢 NULL。
  2. 用完必 `free`。
  3. `free` 即置 `NULL`。
  4. `realloc` 收返回值。
  5. 結構體柔性陣列算總長。
  6. 善用工具查洩漏。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved