Semorphe

自己管記憶體

要多少自己開,用完自己還。 · ⏱ 約 35 分鐘

你會學到三件事

  1. malloc 在執行時才決定要多大
  2. free 用完要還——不還就是漏
  3. sizeof 問「這個型別佔幾個位元組」

開始之前

C 的陣列大小要在寫程式的時候就決定:

int a[5];       // 五格,寫死

而「要幾格」常常要跑起來才知道。C++ 用 vectorC 用 malloc

一、開一塊

int *a = (int*)malloc(5 * sizeof(int));

拆開來看:

這一段 意思
sizeof(int) 一個 int 佔幾個位元組(多半是 4)
5 * sizeof(int) 我要 5 個 int 的空間 = 20 位元組
malloc(20) 給我 20 個位元組,回傳它的地址
(int*) 把那個地址當成「指向 int 的指標」

⚠️ malloc 要的是位元組數,不是格數。malloc(5) 的話你只拿到 5 個位元組——一個 int 都放不滿兩個

⚠️ 不要寫死 malloc(5 * 4) int 不一定是 4 個位元組, 而 sizeof 永遠是對的。

二、用起來跟陣列一樣

for (int i = 0; i < 5; i++) {
    a[i] = i * i;
}
printf("%d\n", a[4]);      // 16

方括號對指標一樣能用——因為 a[i] 的定義就是 *(a + i)

陣列和指標在 C 裡幾乎是同一件事。 差別在於陣列的空間是編譯器給的,malloc 的是你自己要的。

三、🔴 用完要還

free(a);

不還的話那塊空間一直被佔著,直到程式結束。

一支跑一秒的程式漏一點沒差;一支跑一整天的伺服器漏一點, 一天之後記憶體就滿了。這叫記憶體洩漏

⚠️ free 之後不要再用它

free(a);
printf("%d\n", a[0]);      // 🔴 那塊空間已經不是你的了

這叫 use-after-free,而它不一定會當掉——它可能印出一個看起來正常的數字, 因為那塊記憶體還沒被別人拿走。這是最難查的一類 bug。

習慣:free(a); 之後馬上 a = NULL;。這樣再用到就會當場當掉,而不是安靜地錯。

四、⚠️ malloc 可能失敗

記憶體不夠的時候 mallocNULL

int *a = (int*)malloc(n * sizeof(int));
if (a == NULL) {
    printf("記憶體不夠\n");
    return 1;
}

教學程式裡常常省略,而正式的程式不能省

完成的樣子

int main() {
    int *a = (int*)malloc(5 * sizeof(int));
    for (int i = 0; i < 5; i++) {
        a[i] = i * i;
    }
    printf("%d\n", a[4]);
    free(a);
    return 0;
}

換你了

改成讀進使用者輸入的 n,開 n 格,填 1 到 n,印出總和。

這就是 vector 幫你做的事。 做完之後你會知道那顆積木背後是什麼。

這一課你做了什麼

如果卡住了

你看到 多半是因為
只有前一兩格是對的 malloc 的參數忘了乘 sizeof(int)
free 之後還印得出東西 那是巧合。那塊記憶體已經不是你的了
程式跑久了越來越慢 漏了 free
double free 錯誤 同一塊 free 了兩次。free 完設 NULL
在編輯器打開這一課 →