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

C/C++ 內存佈局深度圖解:棧、堆、全局區、常量區、代碼區全攻略

     編輯:關於C語言

一個經典面試題開場


// 情況一:返回字符串字面量指標
char* toStr1() {
    char *s = "abcdefghijkl"; // s 在棧,字符串在常量區
    return s; // 返回常量區地址,安全
}

// 情況二:返回局部數組指標
char* toStr2() {
    char s[] = "abcdefghijkl"; // 整個數組在棧
    return s; // 返回棧地址,函數結束棧幀銷毀 → 野指標!
}

第一個打印正常,第二個印亂碼。核心差異在於字符串字面量存放在常量區(程式結束才釋放),而局部數組存放在棧區(函數返回即釋放)。

程式內存五大區域

區域別名存放內容管理方式生命週期
棧區Stack函數參數、局部變數、返回地址、暫存器保存編譯器自動分配/釋放函數調用期間
堆區Heap動態分配內存程式員手動 malloc/free/new/delete手動控制,程式結束 OS 回收
全局/靜態區Data/BSS全局變數、static 變數編譯器分配,程式結束釋放整個程式運行期間
常量區Literal Pool / .rodata字符串字面量、const 修飾的全局/靜態變數編譯器分配,通常唯讀整個程式運行期間
代碼區Text / .text函數二進制機器碼唯讀,編譯期確定整個程式運行期間

實例圖解:變數去哪兒了?


int a = 0;           // 全局初始化區
char *p1;            // 全局未初始化區

int main() {
    int b;           // 棧
    char s[] = "abc"; // 棧 (數組內容複製自常量區)
    char *p2;        // 棧
    char *p3 = "123456"; // p2在棧,"123456"在常量區
    static int c = 0; // 全局/靜態初始化區
    p1 = malloc(10);  // 堆區 10 bytes
    p2 = malloc(20);  // 堆區 20 bytes
    strcpy(p1, "123456"); // 複製到堆,"123456"在常量區
}

棧 vs 堆:深度對比

維度棧堆
分配方式系統自動程式員手動
效率極快 (指標遞增/遞減)較慢 (鏈表遍歷、碎片整理)
大小限制小 (Windows 預設 1-2MB)大 (受限於虛擬記憶體)
生長方向向低地址向高地址
碎片無有
適用場景小型、生命週期固定的局部變數大型、動態、生命週期不確定的數據

棧溢出典型原因

  • 遞歸過深。
  • 函數內定義大型局部數組 char buf[1024*1024]。
  • 解決:改用靜態/全局/堆分配。

堆分配底層機制

  1. OS 維護空閒塊鏈表。
  2. malloc 遍歷鏈表找首個滿足大小的塊 (First-fit)。
  3. 分割塊:用戶部分 + 剩餘部分重入鏈表。
  4. 塊頭記錄大小,供 free 使用。

存取效率:棧上數組 vs 指標指向字符串


char s1[] = "aaaaaaaaaa"; // 棧上數組
char *s2 = "bbbbbbbbbb";  // 指向常量區

匯編對比 (x86):


; a = s1[1]  -- 直接基址偏移
mov cl, byte ptr [ebp-0Fh]
mov byte ptr [ebp-4], cl

; a = s2[1]  -- 先取指標值,再間接寻址
mov edx, dword ptr [ebp-14h]
mov al, byte ptr [edx+1]
mov byte ptr [ebp-4], al

棧上數組少一次間接寻址,更快。但現代 CPU 快取機制下差異極微,正確性優先。

常見誤區與最佳實踐

  1. 返回局部變數指標/引用 → 絕對禁止。
  2. 釋放後繼續使用 → free(p); p = NULL; 習慣置空。
  3. 重複釋放 → 置空可避免 double free 崩潰。
  4. 記憶體洩漏 → 每個 malloc 對應 free,工具檢查。
  5. 柔性數組結構體 → 結構體末尾放 char data[],單次 malloc 分配整塊,提升緩存局部性。

跨語言共通性

Java、Go、Python、Rust 等語言雖有 GC,但底層同樣有棧 (Stack) 與堆 概念:

  • 值類型、局部引用 → 棧。
  • 對象實例、動態數據 → 堆。
  • 逃逸分析決定對象是否能棧上分配 (Go、JVM、GraalVM)。

理解 C/C++ 手動內存管理,能幫你在任何語言中寫出更高性能、更少 Bug 的代碼。

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