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

C語言動態記憶體分配重溫:malloc/free、堆疊 vs 堆、跨函數記憶體共享

     編輯:關於C

動態記憶體核心觀念:為什麼需要 malloc、如何正確使用、常見陷阱

從靜態陣列限制出發,理解動態分配必要性,掌握 malloc/free 配對、跨函數記憶體傳遞、堆疊與堆的差異。

靜態陣列的五大限制

  1. 大小必須編譯期常數,不可用變數
  2. 無法手動釋放,佔用記憶體直到函數結束
  3. 大小固定,執行期無法擴縮
  4. 生命週期綁定作用域,跨函數共享困難
  5. 大型陣列易造成堆疊溢位

malloc/free 基礎範例

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

void modify(int *p) {
    *p = 200; // 修改動態記憶體內容
    // free(p); // 錯誤!釋放後主程式仍持有指標
}

int main() {
    int *p = (int*)malloc(sizeof(int)); // 分配 4 bytes
    if (!p) { perror("malloc 失敗"); return 1; }
    
    *p = 10;
    printf("修改前: %d\n", *p); // 10
    
    modify(p); // 傳遞指標,共享同一塊記憶體
    printf("修改後: %d\n", *p); // 200
    
    free(p); // 歸還給堆
    // printf("%d\n", *p); // 錯誤!使用已釋放記憶體 (UAF)
    p = NULL; // 防野指標
    
    return 0;
}

堆疊 vs 堆 對照表

特性堆疊堆
管理方式編譯器自動程式設計師手動
分配速度極快 (指標移動)較慢 (搜尋/分割/鎖)
大小限制小 (通常 1-8MB)大 (虛擬記憶體上限)
生命週期作用域結束自動釋放malloc 到 free 為止
碎片化無有 (外部/內部)
適用場景區域變數、函數呼叫、小物件大資料、動態大小、跨作用域共享

跨函數共享記憶體:正確模式

// 配置端負責 malloc,使用端負責 free (所有權轉移)
int *createBuffer(int size) {
    return (int*)malloc(size * sizeof(int));
}

void processBuffer(int *buf, int size) {
    for (int i = 0; i < size; i++) buf[i] = i * i;
}

void destroyBuffer(int *buf) {
    free(buf);
}

int main() {
    int *data = createBuffer(100);
    processBuffer(data, 100);
    destroyBuffer(data); // 明確釋放
    return 0;
}

常見錯誤與後果

錯誤現象嚴重度
未檢查 malloc 回傳值解引用 NULL → 崩潰致命
free 後繼續使用 (UAF)資料損毀、安全漏洞致命
重複 free (Double Free)堆破壞、崩潰致命
free 非 malloc 指標未定義行為、崩潰致命
記憶體洩漏 (忘記 free)記憶體耗盡、效能下降嚴重
緩衝區溢位覆蓋相鄰資料、安全漏洞致命

進階主題

  • realloc:調整大小,可能移動記憶體,必須用暫存變數接收
  • calloc:分配並歸零,防洩漏敏感資料
  • aligned_alloc / posix_memalign:指定對齊 (SIMD、硬體暫存器)
  • 記憶體池/物件池:高頻分配小物件的效能優化
  • Valgrind/ASan:動態偵測記憶體錯誤的必備工具

嵌入式系統特別提醒

  • 避免動態分配 (無 MMU、碎片風險、確定性需求)
  • 改用靜態陣列、記憶體池、連結清單靜態節點陣列
  • 若必須動態,實作專用分配器 (TLSF、bitmap 分配器)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved