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

C 語言動態記憶體管理完整指南:malloc、calloc、realloc 與 free 詳解

     編輯:C 語言入門

C 語言動態記憶體管理完整指南

在 C 語言程式設計中,記憶體管理是核心技能之一。不同於高階語言擁有自動垃圾回收機制,C 語言要求程式設計師手動掌控記憶體的分配與釋放。這篇文章將系統性地介紹 <stdlib.h> 標頭檔中提供的四大動態記憶體管理函式:malloc()、calloc()、realloc() 與 free(),並透過實戰範例展示它們的正確用法與常見陷阱。

核心函式速查表

函式原型功能描述關鍵特性
void *malloc(size_t size)分配指定位元組數的記憶體塊內容未初始化(包含隨機垃圾值)
void *calloc(size_t num, size_t size)分配陣列記憶體(元素數 × 元素大小)自動將所有位元歸零初始化
void *realloc(void *ptr, size_t new_size)調整已分配記憶體塊的大小可擴大或縮小;可能移動記憶體位址
void free(void *ptr)釋放先前分配的記憶體塊防止記憶體洩漏;釋放後指標變成野指標

動態分配記憶體:從固定大小到彈性管理

當陣列大小在編譯時期無法確定時,動態分配成為唯一解法。例如讀取不定長度的使用者輸入:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    char name[100] = "Zara Ali";
    char *description = NULL;

    /* 分配 200 位元組空間 */
    description = (char *)malloc(200 * sizeof(char));
    if (description == NULL) {
        fprintf(stderr, "錯誤:無法分配所需記憶體\n");
        return 1;
    }

    strcpy(description, "Zara ali a DPS student in class 10th");
    printf("Name = %s\n", name);
    printf("Description: %s\n", description);

    /* 釋放記憶體,良習必養 */
    free(description);
    description = NULL; // 避免野指標
    return 0;
}

關鍵提醒: malloc 回傳 void*,雖然 C 語言允許隱性轉型,但加上 (char *) 強制轉型可提升碼可讀性與 C++ 相容性。永遠檢查回傳值是否為 NULL,這是防禦性程式設計的基本原則。

calloc:自動歸零的安全選擇

當需要初始化為零的陣列時,calloc 比 malloc + memset 更簡潔:

/* 分配 200 個 char 並自動歸零 */
description = (char *)calloc(200, sizeof(char));

兩者效能差異極小,calloc 在大塊記憶體分配時可能因零頁最佳化而更快。

realloc:彈性調整記憶體大小

當資料量超出預期,realloc 可在保留原有資料的前提下擴充記憶體:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    char *description = (char *)malloc(30 * sizeof(char));
    if (!description) return 1;

    strcpy(description, "Zara ali a DPS student.");
    printf("原始: %s\n", description);

    /* 擴充至 100 位元組 */
    char *temp = (char *)realloc(description, 100 * sizeof(char));
    if (temp == NULL) {
        free(description); // realloc 失敗時原記憶體仍有效
        return 1;
    }
    description = temp; // 重要:更新指標,realloc 可能返回新位址

    strcat(description, " She is in class 10th");
    printf("擴充後: %s\n", description);

    free(description);
    return 0;
}

致命錯誤避坑指南:

  • 別直接寫 ptr = realloc(ptr, ...):若失敗會導致原記憶體位址遺失,造成記憶體洩漏。務必使用暫存變數接收回傳值。
  • 縮小記憶體同樣危險:縮減大小後,超出範圍的資料會被截斷,確認邏輯無誤再操作。

記憶體釋放與程式結束

雖然作業系統會在程式結束時回收所有記憶體,但長期運行的程式(如伺服器、嵌入式裝置)必須在不需要時立即呼叫 free()。良好的習慣:

  1. 配對原則:每個 malloc/calloc/realloc 對應一個 free。
  2. 釋放後歸零:free(ptr); ptr = NULL; 防止野指標二次釋放或誤用。
  3. 避免重複釋放:對同一指標呼叫兩次 free 會導致未定義行為。

常見錯誤與最佳實踐總結

錯誤類型錯誤程式碼正確做法
未檢查 NULLp = malloc(100); strcpy(p, "hi");檢查 if (!p) { handle_error(); }
釋放後繼續使用free(p); printf("%s", p);free(p); p = NULL;
realloc 直接賦值p = realloc(p, 200);使用暫存變數 tmp = realloc(...)
釋放非堆疊記憶體char *p = "hello"; free(p);僅釋放 malloc/calloc/realloc 取得的位址

結語

掌握動態記憶體管理是從 C 語言初學者邁向系統級程式設計師的關鍵門檻。記住三大鐵律:檢查回傳值、配對釋放記憶體、釋放後歸零指標。配合 Valgrind、AddressSanitizer 等工具偵測記憶體洩漏與越界存取,能讓你的 C 程式碼更健壯、更專業。

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