以下是您提供的英文文本翻译成繁體中文的版本:

C - Memory Management

# C 語言的記憶體管理

你好,未來的編程魔法師!今天,我們將深入探討 C 語言中記憶體管理的迷人世界。如果你是編程新手,別擔心;我會一步步引導你走過這段旅程,就像我這些年來對無數學生所做的一樣。所以,戴上你的虛擬安全帽,讓我們一起探索計算機記憶體的建築工地!

## C 語言中的動態記憶體管理函數

在我們開始建造記憶體摩天大樓之前,讓我們先熟悉一下我們將要使用的工具。在 C 語言中,我們有一組函數幫助我們動態管理記憶體。將這些函數想像成你可靠的工具箱:

| 函數     | 目的                     |
|----------|--------------------------|
| malloc() | 分配一塊記憶體           |
| calloc() | 分配並初始化多塊記憶體   |
| realloc() | 放大或縮小先前分配的記憶體塊 |
| free()   | 將分配的記憶體释放回系統   |

這些函數就像我們記憶體建築的施工隊伍。每個都有其特殊的任務,我們將親自了解它們。

## 動態分配記憶體

想像你正在計劃一個派對,但你不知道會有多少賓客來。這就是動態記憶體分配派上用場的地方!你可以根據需要增加或減少椅子,而不是設定一個固定的數量。讓我們看看在 C 語言中如何做到這點。

### malloc() 函數

我們的第一個記憶體分配超人是 `malloc()`。它代表“記憶體分配”,並用於從系統請求一塊記憶體。

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

int main() {
    int *numbers;
    int size = 5;

    numbers = (int*)malloc(size * sizeof(int));

    if (numbers == NULL) {
        printf("記憶體分配失敗!\n");
        return 1;
    }

    for (int i = 0; i < size; i++) {
        numbers[i] = i * 10;
        printf("numbers[%d] = %d\n", i, numbers[i]);
    }

    free(numbers);
    return 0;
}

讓我們分解這段代碼:

  1. 我們包含 <stdlib.h>,因為這是 malloc() 所在的地方。
  2. 我們聲明一個指標 numbers 來存儲我們動態分配的數組。
  3. malloc(size * sizeof(int)) 請求足夠的記憶體來存放 5 個整數。
  4. 我們將結果轉換為 (int*),因為 malloc() 返回一個 void 指標。
  5. 檢查 malloc() 是否成功!如果它返回 NULL,我們就沒有運氣(和記憶體)。
  6. 現在我們可以使用 numbers,就像一個普通的數組一樣。
  7. 不要忘記在使用完畢後 free() 記憶體!

calloc() 函數

現在,認識一下 calloc(),動態記憶體分配中的整理達人。當 malloc() 給你之前在那裡的垃圾記憶體時,calloc() 會清理自己的後路,將所有分配的記憶體初始化為零。

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

int main() {
    int *numbers;
    int size = 5;

    numbers = (int*)calloc(size, sizeof(int));

    if (numbers == NULL) {
        printf("記憶體分配失敗!\n");
        return 1;
    }

    for (int i = 0; i < size; i++) {
        printf("numbers[%d] = %d\n", i, numbers[i]);
    }

    free(numbers);
    return 0;
}

這裡的主要區別在於:

  1. calloc() 接受兩個參數:元素數量和每個元素的大小。
  2. 所有元素都初始化為零,所以我們的輸出將全部是零。

調整和釋放記憶體

有時候,我們的派對會比預期的大或小。這時 realloc() 就派上用場了!

realloc() 函數

realloc() 像個魔術師,能夠擴大或縮小我們的記憶體塊。

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

int main() {
    int *numbers;
    int size = 5;

    numbers = (int*)malloc(size * sizeof(int));

    if (numbers == NULL) {
        printf("記憶體分配失敗!\n");
        return 1;
    }

    for (int i = 0; i < size; i++) {
        numbers[i] = i * 10;
        printf("numbers[%d] = %d\n", i, numbers[i]);
    }

    // 讓我們擴展我們的數組
    size = 10;
    numbers = (int*)realloc(numbers, size * sizeof(int));

    if (numbers == NULL) {
        printf("記憶體重新分配失敗!\n");
        return 1;
    }

    // 填充新的元素
    for (int i = 5; i < size; i++) {
        numbers[i] = i * 10;
    }

    // 打印所有元素
    for (int i = 0; i < size; i++) {
        printf("numbers[%d] = %d\n", i, numbers[i]);
    }

    free(numbers);
    return 0;
}

這裡發生了什麼:

  1. 我們從 5 個元素開始,就像之前一樣。
  2. 我們使用 realloc() 擴展我們的數組到 10 個元素。
  3. realloc() 保持我們原始數據的完整,並給我們更多的空間。
  4. 我們填充新的元素並打印出來。

free() 函數

最後但同樣重要的是,我們有 free(),我們記憶體管理團隊的清潔隊。記住總是要在用完分配的記憶體後 free() 它!

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

int main() {
    int *numbers = (int*)malloc(5 * sizeof(int));

    if (numbers == NULL) {
        printf("記憶體分配失敗!\n");
        return 1;
    }

    for (int i = 0; i < 5; i++) {
        numbers[i] = i * 10;
        printf("numbers[%d] = %d\n", i, numbers[i]);
    }

    free(numbers);  // 清理!
    numbers = NULL; // 好習慣,避免使用已釋放的記憶體

    // 現在嘗試使用 'numbers' 會是一個壞主意!

    return 0;
}

記住:

  1. 總是要 free() 你分配的記憶體,當你用完它時。
  2. 在釋放後將指標設為 NULL,以避免意外使用已釋放的記憶體。
  3. 永遠不要嘗試 free() 你沒有動態分配的記憶體。

這就是全部,各位!我們已經建造了我們的記憶體管理摩天大樓,學會了如何為我們的派對賓客分配空間,根據需要重新安排場地,以及之後清理。記住,良好的記憶體管理就像是一個好主人——總是確保你有足夠的空間為你的賓客,對場地安排保持靈活,派對結束後徹底清理!

繼續練習這些概念,很快你將成為程序記憶體的主建筑师。快樂編程,願你的程序永遠無泄漏!

Credits: Image by storyset