0Pricing
C Academy · レッスン

reallocで拡張する

動的配列のサイズを変更します。

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

mallocだけでは足りないとき

配列を確保して値を格納した後で、もっと広い領域が必要だとわかることがあります。末尾を越えて書き込むことはできません。

reallocを使うと、既存のヒープ領域のサイズを変更し、すでに格納されているデータを保持できます。

reallocのシグネチャ

realloc(ptr, new_bytes)には、元のポインターと新しい合計サイズ(バイト単位)を渡します。

新しいサイズの領域へのポインターが返されます。データの先頭部分は、元のサイズと新しいサイズの小さい方まで保持されます。

int *bigger = realloc(a, new_n * sizeof(*a));

領域が移動することがある

reallocは領域をその場で拡張することもあれば、新しい領域を確保してデータをコピーし、古い領域を解放することもあります。

いずれの場合も、元のポインターは無効になる可能性があります。以降は、返されたポインターを使わなければなりません。

a = realloc(a, new_n * sizeof(*a));
/* the old value of a may no longer be valid */

自己代入の落とし穴

a = realloc(a, ...)と書くと簡潔に見えますが危険です。reallocがNULLを返した場合、aが上書きされ、元のポインターを失って古い領域がリークします。

代わりに一時変数を使ってください。

int *tmp = realloc(a, new_n * sizeof(*a));
if (tmp == NULL) { /* a is still valid */ return 1; }
a = tmp;

安全に配列を拡張する

このプログラムは3個のintを確保し、reallocで6個に拡張します。最初の3つの値は保持されます。

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

int main(void) {
    int *a = malloc(3 * sizeof(*a));
    if (!a) return 1;
    for (int i = 0; i < 3; i++) a[i] = i + 1;

    int *tmp = realloc(a, 6 * sizeof(*a));
    if (!tmp) { free(a); return 1; }
    a = tmp;

    for (int i = 3; i < 6; i++) a[i] = i + 1;
    for (int i = 0; i < 6; i++) printf("%d\n", a[i]);
    free(a);
    return 0;
}

追加されたバイトは未初期化

領域を拡張すると、末尾に追加された領域には、新しくmallocで確保したメモリと同じように不定の値が入っています。

reallocは既存のデータを保持しますが、新しい領域をゼロ初期化することはありません。読み取る前に初期化してください。

a = realloc(a, 6 * sizeof(*a));
for (int i = 3; i < 6; i++) a[i] = 0;  /* clear new slots */

倍増戦略

要素を1つ追加するたびにreallocを呼び出すと低速です。典型的な方法は、空きがなくなるたびに容量を2倍にすることです。

これにより、配列の拡張中にreallocを呼び出す回数を少なくでき、平均的に高い性能が得られます。

if (count == cap) {
    cap = cap ? cap * 2 : 4;
    int *tmp = realloc(a, cap * sizeof(*a));
    if (!tmp) { free(a); return 1; }
    a = tmp;
}

追加しながら配列を構築する

このプログラムは空の状態から始め、必要に応じて容量を2倍にしながら数値を追加します。

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

int main(void) {
    int *a = NULL;
    size_t count = 0, cap = 0;
    for (int v = 1; v <= 5; v++) {
        if (count == cap) {
            cap = cap ? cap * 2 : 2;
            int *tmp = realloc(a, cap * sizeof(*a));
            if (!tmp) { free(a); return 1; }
            a = tmp;
        }
        a[count++] = v;
    }
    for (size_t i = 0; i < count; i++) printf("%d\n", a[i]);
    free(a);
    return 0;
}

realloc(NULL, n)はmallocと同じように動作する

ポインターにNULLを渡すと、reallocはmallocとまったく同じように動作します。

倍増ループの最初にa = NULLとしても動作するのはこのためです。最初のreallocが初期領域を確保します。

int *a = NULL;
a = realloc(a, 4 * sizeof(*a));  /* same as malloc(4 * sizeof(*a)) */

領域を縮小する

reallocを使って領域を小さくすることもできます。新しいサイズまでのデータは保持され、それ以降は破棄されます。

縮小によってメモリが返される場合もありますが、実装によっては大きい領域を保持することもあります。

int *tmp = realloc(a, 2 * sizeof(*a));  /* down from more */
if (tmp) a = tmp;

計算でのオーバーフローを避ける

容量が大きくなると、cap * sizeof(*a)の計算結果がsize_tの範囲を超え、小さな値にラップアラウンドする可能性があります。

非常に大きな配列では、乗算がオーバーフローしないか確認するか、利用できるシステムではreallocarrayを使用してください。

if (cap > SIZE_MAX / sizeof(*a)) { /* overflow */ return 1; }
int *tmp = realloc(a, cap * sizeof(*a));

クイックチェック

reallocについての理解度を確認しましょう。

まとめ

reallocはヒープブロックのサイズを変更し、別の場所へ移動する場合があるため、必ず返されたポインターを使用してください。

失敗しても元のブロックをリークさせないよう、一時変数に代入します。速度を上げるには容量を2倍ずつ増やし、新しいスロットを初期化し、realloc(NULL, n)はmallocと同じであることを覚えておいてください。次は、このロジックを再利用可能なベクター型でラップします。

よくある質問

「reallocで拡張する」レッスンは無料ですか?

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

「reallocで拡張する」で何を学びますか?

動的配列のサイズを変更します。 ブラウザで直接実行するハンズオンコードでC Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

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

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

「reallocで拡張する」レッスンにはどのくらい時間がかかりますか?

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

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

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

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

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