| 函數 | 原型 | 特性 | 初始化 |
|---|---|---|---|
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);
int *p = malloc(100); // 可能返回 NULL
p[0] = 1; // 如果 NULL -> Segfault
✅ **永遠檢查**:`if (!p) handle_oom();`
free(p);
p[0] = 1; // UB: Use After Free (UAF)
free(p); // UB: Double Free
✅ **釋放即置空**:`free(p); p = NULL;`
realloc(p, 200); // 如果移動了,p 變懸空指針,新塊洩漏
✅ **臨時變數接收**:`void *tmp = realloc(p, 200); if (tmp) p = tmp; else handle_oom();`
// C: void* 隱式轉換任意指針,無需轉型 (轉型反而隱藏漏 include 警告)
int *p = malloc(sizeof(int) * 10); // C 標準寫法
// C++: 必須強轉
int *p = (int*)malloc(sizeof(int) * 10); // 或 static_cast
// 建議跨語言頭檔用宏統一
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 無空間