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

C語言動態記憶體分配完全指南:malloc、free 原理與實戰應用

     編輯:關於C語言

為什麼需要動態記憶體分配

靜態分配缺陷


float score[30];  // 固定大小陣列

問題:

  • 編譯期必須決定大小,執行期無法調整
  • 實際需求未知時,只能宣告「夠大」陣列 → 浪費記憶體
  • 需求超過宣告大小 → 下標越界、崩潰、安全漏洞
  • 需求變動需修改原始碼重新編譯

動態分配優勢

  1. 無需預先分配:執行期按需申請
  2. 大小彈性:可隨時擴大/縮小(配合 realloc)
  3. 精確配置:恰好滿足需求,無浪費

核心函數:malloc 與 free

malloc - 記憶體分配

原型:void *malloc(size_t size);
功能:在堆區分配 size 位元組連續空間
參數:無號整數(位元組數)
返回值:指向分配區起始位址的 void* 指標;失敗返回 NULL

free - 記憶體釋放

原型:void free(void *ptr);
功能:釋放 ptr 指向的先前由 malloc/calloc/realloc 分配的區塊
參數:必須是先前分配函數返回的指標值
警告:傳遞其他值 → 未定義行為(崩潰、資料損毀)

malloc 使用完整範例


#include 
#include 

main() {
    int count, *array;
    // 分配 10 個 int 空間(10 * 4 bytes = 40 bytes)
    if ((array = (int *)malloc(10 * sizeof(int))) == NULL) {
        printf("無法分配記憶體空間。\n");
        exit(1);
    }
    // 賦值
    for (count = 0; count < 10; count++)
        array[count] = count;
    // 列印
    for (count = 0; count < 10; count++)
        printf("%2d", array[count]);
    // 釋放(良好習慣)
    free(array);
}

if 條件拆解

  1. malloc(10 * sizeof(int)):分配空間,返回 void*
  2. (int *):強制轉型為 int*
  3. array = ...:指派給指標變數
  4. == NULL:檢查分配是否成功

free 關鍵規則:指標值而非變數


int *p1, *p2;
p1 = malloc(10 * sizeof(int));
p2 = p1;           // p2 指向同一區塊
// ... 使用記憶體 ...
free(p2);          // 正確:釋放 p2 指向的區塊(等同 free(p1))
// free(p1);        // 錯誤:重複釋放!

核心:free 看的是指標值(位址),而非指標變數本身。同一區塊只能釋放一次。

動態分配管理雙引擎

兩者配合實現記憶體動態租用與歸還循環。

擴展函數:calloc、realloc

函數角色比喻
malloc分配新區塊租房子
free歸還區塊退房子
函數原型特性
callocvoid *calloc(size_t n, size_t size)分配 n 个 size 位元組區塊,自動歸零
reallocvoid *realloc(void *ptr, size_t size)調整現有區塊大小(擴大/縮小),保留原資料

realloc 使用模式


int *p = malloc(10 * sizeof(int));
// ... 使用 ...
p = realloc(p, 20 * sizeof(int));  // 擴大為 20 個 int
if (p == NULL) { /* 處理失敗 */ }
// 原前 10 個元素值保留,新增 10 個未初始化

實務最佳實踐

  1. 永遠檢查 malloc 返回值:失敗處理(exit、重試、降級)
  2. 配對 free:每個 malloc 對應一個 free,避免洩漏
  3. 釋放後置 NULL:free(p); p = NULL; 防止野指標誤用
  4. 使用 sizeof(型態):malloc(n * sizeof(int)) 而非硬編碼位元組數
  5. 避免在迴圈中頻繁 malloc/free:效能差,改用記憶體池或批次分配
  6. 大型分配考慮對齊:posix_memalign、aligned_alloc
  7. 嵌入式系統:可能無 malloc,使用靜態池或自定義分配器

常見錯誤與後果

動態分配實戰:可變長度字串陣列


char **read_lines(int *count) {
    char **lines = NULL;
    char buf[256];
    *count = 0;
    while (fgets(buf, sizeof(buf), stdin)) {
        lines = realloc(lines, (*count + 1) * sizeof(char *));
        lines[*count] = malloc(strlen(buf) + 1);
        strcpy(lines[*count], buf);
        (*count)++;
    }
    return lines;
}

void free_lines(char **lines, int count) {
    for (int i = 0; i < count; i++) free(lines[i]);
    free(lines);
}

總結

  1. 靜態陣列固定大小、編譯期決定,動態分配執行期彈性配置
  2. malloc(size) 分配位元組,返回 void*,失敗返回 NULL
  3. free(ptr) 釋放,參數必為 malloc 系返回值,同一區塊只能 free 一次
  4. 永遠檢查 NULL、配對 free、免後置 NULL — 三大鐵律
  5. calloc 歸零分配,realloc 調整大小保留資料
  6. 動態分配是鏈表、樹、圖、動態陣列等資料結構基石
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
錯誤後果修正
未檢查 NULL解參考 NULL → 段錯誤必加 if 判斷
重複 free堆損毀、崩潰free 後置 NULL
free 非 malloc 指標未定義行為只 free malloc 返回值
記憶體洩漏可用記憶體耗盡所有路徑確保 free
使用已釋放記憶體資料損毀、安全漏洞free 後置 NULL
柔性陣列成員誤用越界寫入正確計算總大小