動態記憶體分配是 C 語言核心機制之一,stdlib.h 提供的三大函式 malloc、calloc、realloc 雖同屬堆區操作,但初始化行為、擴容策略、適用場景截然不同。本文結合原始碼實測,為你釐清關鍵差異與避坑指南。
void* malloc(size_t size);
void* calloc(size_t numElements, size_t sizeOfElement);
void* realloc(void* ptr, size_t newSize);
三者回傳值均為分配記憶體的起始位址,失敗回傳 NULL。
size 位元組連續空間void* 需強制轉型(C++ 必須,C 可隱式)numElements * sizeOfElement 位元組,並將每個位元設為 0memset 步驟ptr 重新調整至 newSizeptr=NULL 等同 malloc;newSize=0 等同 free(實作相關)char *p = malloc(10), *q = p;
p = realloc(p, 10); // 仍在同一頁面
// 輸出:p=0x431a70, q=0x431a70 (位址未變)
char *p = malloc(10), *q = p;
p = realloc(p, 1000); // 空間不足,尋找新塊
// 輸出:p=0x351c0, q=0x431a70 (位址改變!q 成懸空指標)
教訓:永遠寫 p = realloc(p, ...),切勿保留舊指標備份。
當原記憶體塊後方空間不足時,分配器會:
這意味著:資料可能被物理移動,指向舊記憶體內部的指標(如結構體內部指標、陣列元素位址)全部失效。設計資料結構時應儘量使用相對偏移而非絕對位址。
| 場景 | 推薦函式 | 理由 |
|---|---|---|
| 單一變數/結構體分配 | malloc | 輕量、語意明確 |
| 陣列/大量同質元素 | calloc | 自動歸零、防止未初始化讀取 |
| 緩衝區動態增減 | realloc | 避免手動 malloc+copy+free,但注意位址遷移 |
| 安全釋放 | free(ptr); ptr=NULL; | 防雙重釋放、懸空指標誤用 |
記住:動態記憶體管理的鐵律是「誰分配、誰釋放、誰負責初始化」。善用 valgrind、AddressSanitizer 等工具在開發期攔截記憶體錯誤,將大幅降低上線風險。