動態記憶體管理

檢查 malloc 的回傳是否為 NULL

malloc 是一個請求,而請求可能被拒絕。若系統找不到足夠的記憶體來滿足你的呼叫,malloc 不會當機也不會丟出錯誤——它只是回傳 NULL,一個代表沒給你記憶體的空指標。檢查 NULL 就是在使用指標前先測試是否為 NULL 的習慣,因為把一個 NULL 指標當成真實記憶體來用,是一場等著發生的當機。

精確地說:每次 malloc、calloc 或 realloc 之後,你都應該把回傳的指標與 NULL 比較。若它是 NULL,配置失敗、指標什麼都不指向;解參考它(透過它讀或寫)是未定義行為,在大多數系統上意味著立即的記憶體區段錯誤,但也可能更糟。正確的模式是當場處理失敗——回傳錯誤、清理你已配置的任何東西,或者對一個無事可做的小程式而言,印出訊息並結束。唯有在你確認指標不是 NULL 之後,才開始寫入該區塊。略過這項檢查是初學者 C 中最常見的疏漏之一,而它通常不被注意,因為在記憶體充裕的現代機器上 malloc 很少失敗——直到某天請求極大、或大小計算溢位了、或機器真的記憶體耗盡,程式就在那個未防護的解參考處當機。

兩個誠實的細節。第一,在過度承諾記憶體的系統上(許多 Linux 設定如此),即使記憶體無法全部對應,malloc 仍可能成功並回傳非 NULL 的指標——失敗於是稍後以行程被殺掉的形式浮現,而不是 malloc 回傳 NULL。所以檢查 NULL 是必要的,但在每個系統上並非完整的保證。第二,失敗的 realloc 回傳 NULL 卻保留原始區塊完好,所以你必須把它檢查進一個暫時變數,以免洩漏原始區塊。這項紀律很簡單、值得養成自動反應:絕不在先確認不是 NULL 之前就使用一個剛配置的指標。

int *p = malloc(n * sizeof *p); if (p == NULL) { /* 配置失敗 */ fprintf(stderr, "記憶體不足\n"); return -1; /* 處理它;不要碰 p */ } p[0] = 1; /* 唯有檢查之後才安全 */

使用前永遠把結果與 NULL 比對;NULL 解參考正是這項檢查所防止的當機。

在過度承諾的系統上,即使記憶體短缺 malloc 仍可能回傳非 NULL,所以這項檢查是必要的、但並非處處都是完整保證。仍要永遠檢查——否則失敗就是一次未定義行為的當機。

又稱
checking for allocation failureguarding malloc配置失敗檢查