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

C語言內存佈局全景圖:棧、堆、靜態區、常量區、代碼區深度解析

     編輯:關於C語言

C語言內存佈局全景圖:棧、堆、靜態區、常量區、代碼區深度解析

搞懂 C 程序內存五大區域的特性、生命週期、分配方式,是寫出無內存錯誤代碼的前提。本文結合代碼驗證,系統梳理每一區的「性格」與「避坑指南」。

五大區域對比速查表

區域存放內容生命週期管理方式典型例子
棧局部變量、函數參數、返回地址作用域結束自動銷毀編譯器自動管理(先進後出)int a; char buf[10];
堆動態分配內存手動申請/釋放程序員管理(malloc/free)int *p = malloc(100);
靜態區全局變量、static 變量程序啟動到結束編譯器分配,默認 0 初始化static int cnt; global_var;
常量區字符串字面值、const 修飾的全局變量程序全周期只讀,**不可修改**"hello", 'c', 3.14
代碼區二進制機器指令(函數體)程序全周期只讀,可共享void func() { ... }

代碼驗證關鍵行為

1. 棧 vs 堆地址增長方向

int a = 10;
const int m = 10;
int *b = malloc(sizeof(int) * 2);
printf("&m=%p, &a=%p, b=%p\n", &m, &a, b);  
// 典型輸出:棧地址高,堆地址低(或相反,視架構),但棵增長方向固定

2. static 變量只初始化一次

void test3() {
    static int a = 10;  // 僅首次調用執行賦值
    a++;
    printf("%d\n", a);  // 輸出 11, 12, 13...
}
test3(); test3(); test3();

3. 常量區不可寫——編譯期 vs 運行期陷阱

char *str = "iphone";   // str 指向常量區,不可寫
char str1[] = "iphone"; // str1 在棧,內容是常量區拷貝,可寫
str1[0] = 'I';  // ✅ 合法
str[0] = 'I';   // ❌ 運行期崩潰(段錯誤)
// 防禦:const char *str = "...";  // 編譯期報錯,更早發現

4. 內存分配函數家族

函數特性適用場景
malloc不初始化,殘留舊數據大塊內存、後續會覆寫
calloc自動歸零,較慢需要零初始化的結構體/數組
realloc擴容/縮容,可能移動內存動態增長的緩衝區
memset按字節填充字符數組初始化、結構體歸零
memcpy內存拷貝,不關心類型任意類型數據移動
memcmp內存比較二進制數據塊比較

實戰案例:提取字符串中數字並動態存儲

char *str = "iphone6and8Plus23cc84";
int count = 0;
// 第一遍:統計數字個數
for (int i = 0; i < strlen(str); i++)
    if (isdigit(str[i])) count++;

int *num = malloc(sizeof(int) * count);  // 精確分配
count = 0;
// 第二遍:提取轉換
for (int i = 0; i < strlen(str); i++)
    if (isdigit(str[i]))
        num[count++] = str[i] - '0';  // '0'=48,比 48 可讀

// 使用後釋放
free(num); num = NULL;

安全鐵律

  1. free(ptr); ptr = NULL; —— 防雙重釋放、野指針
  2. 字符串操作永遠 strlen+1 分配
  3. 大塊內存優先 calloc 避免未初始化讀取
  4. realloc 必須用臨時變量接收返回值,防失敗丟失原指針

內存管理無小事,將五大區特性刻入肌肉記憶,才能在指針叢林中從容穿行。

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