C Academy · レッスン

解放してリークを防ぐ

正しく後片付けします。

レッスン 4/413 ステップ

「解放してリークを防ぐ」はCoddyKit上の無料C Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C Academyコースには全4レッスンが含まれています。

すべてのmallocにはfreeが必要

ヒープメモリは、freeで解放するまで確保されたままです。ブロックを指す唯一のポインターを、解放せずに失うと、そのメモリはリークします。

リークは時間とともに蓄積し、長時間動作するプログラムではメモリを使い果たす可能性があります。

int *a = malloc(100 * sizeof(*a));
/* ... use a ... */
free(a);

freeが実際に行うこと

free(p)はブロックをアロケーターに返し、再利用できるようにします。ただし、p自体の値は変更しません。

freeの後もpは古いアドレスを指したままですが、そのアドレスは無効になっています。そこにアクセスすると未定義動作になります。

free(p);
/* p is now a dangling pointer */

ダングリングポインターの罠

解放後のポインターを使用することは、use-after-freeバグです。一見正常に動作しても、その後データを破壊したり、予測不能なタイミングでクラッシュしたりする可能性があります。

簡単な対策は、解放直後にポインターをNULLへ設定することです。

free(a);
a = NULL;   /* now misuse is a clean NULL deref, easier to catch */

二重解放は未定義動作

同じブロックに対してfreeを2回呼び出すと、アロケーターの内部状態が壊れ、多くの場合クラッシュします。

最初のfreeの後にポインターをNULLへ設定すると、free(NULL)は明示的に安全で何もしないため、二重解放を防ぐ助けになります。

free(a);
a = NULL;
free(a);   /* free(NULL) is a harmless no-op */

mallocしたものだけをfreeする

freeには、malloc、calloc、またはreallocから返されたポインターだけを渡してください。

スタック変数のアドレス、文字列リテラル、またはブロックの途中を指すポインターを解放すると、未定義動作になります。

int x = 5;
/* free(&x);   WRONG: x is on the stack */
int *p = malloc(sizeof(int));
free(p);        /* correct */

早期returnによるリーク

よくあるリークの例は、メモリを確保した後、解放する前にエラー処理の経路でreturnしてしまうことです。その結果、ブロックが失われます。

メモリを所有しているすべての終了経路で、先に解放するようにしてください。

int *a = malloc(n * sizeof(*a));
if (something_failed) {
    free(a);   /* don't forget this before returning */
    return -1;
}

確保と解放を適切に行うプログラム

このプログラムは、どの経路でもメモリを確保して使用し、解放するため、何もリークしません。

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

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

入れ子になった確保の解放

あるブロックが他のブロックへのポインターを含んでいる場合は、内側のブロックを先に解放し、その後で外側のブロックを解放します。

外側のブロックを先に解放すると、内側のブロックのアドレスを失い、それらがリークしてしまいます。

for (size_t i = 0; i < rows; i++)
    free(grid[i]);   /* free each row first */
free(grid);          /* then the array of pointers */

各ブロックに1つの所有者

各メモリ確保を所有し、解放する責任を負うコードの部分を決めてください。

2つのポインターが同じブロックを指していて、両方が解放すると二重解放になります。所有者を明確にすれば、これを防げます。

ツールでリークを検出する

リークを目視で探す必要はありません。valgrindやAddressSanitizerなどのツールは、行番号付きでリークや無効なfreeを報告します。

-gを付けてコンパイルし、ツール上で実行すると、何が解放されなかったのかを正確に確認できます。

/* gcc -g -fsanitize=address prog.c && ./a.out */
/* or: valgrind --leak-check=full ./a.out */

セットアップと逆の順序で解放する

信頼できる習慣として、複数のリソースを取得する関数では、取得した順序と逆の順序で解放してください。

これは依存関係を構築した順序を反映するため、クリーンアップを予測しやすくできます。

char *buf = malloc(64);
int  *idx = malloc(64 * sizeof(int));
/* ... use them ... */
free(idx);   /* free last-acquired first */
free(buf);

クイックチェック

メモリの解放についての理解度を確認しましょう。

まとめ

すべてのコード経路で、各メモリ確保とちょうど1回のfreeを対応させてください。

解放後にポインターをNULLへ設定し、ダングリングポインターと二重解放を避けます。入れ子になった確保は内側から先に解放し、各ブロックに1つの所有者を割り当て、valgrindやASanを使ってリークを検出してください。これで動的配列を扱うためのツールキットが一通り揃いました。

無料で開始

AI チューターと学ぶ C — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
39
レッスン
144

よくある質問

「解放してリークを防ぐ」レッスンは無料ですか?

はい。「解放してリークを防ぐ」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C Academyコースには全4レッスンが含まれています。

「解放してリークを防ぐ」で何を学びますか?

正しく後片付けします。 ブラウザで直接実行するハンズオンコードでC Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「解放してリークを防ぐ」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC Academyレッスンでコードを書いて実行できますか?

はい。すべてのC Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 配列を確保する
  2. reallocで拡張する
  3. 再利用可能なベクター型
  4. 解放してリークを防ぐ
← C Academyに戻る