本文へスキップ
BecomeCoder

C言語コース · 第8章 動的メモリ管理 · レッスン32

calloc/realloc ― ゼロ初期化と後からの拡張

ブラウザで完結

導入

malloc で確保したメモリの中身は不定(ゴミが入っている可能性がある)です。最初から 0 にしておきたいときは calloc を使います。また「最初は3個で確保したが、後から5個に増やしたい」というときは realloc確保済みの領域を拡張できます。

説明

calloc(個数, 1個のバイト数) は、確保と同時に全バイトを 0 にします。realloc(元のポインタ, 新しいバイト数) は、元のデータを保ったまま領域を大きく(または小さく)します。

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

int main(void) {
    int *arr = calloc(3, sizeof(int));    // 0, 0, 0 で確保される
    arr[0] = 1;
    arr[1] = 2;
    arr[2] = 3;

    arr = realloc(arr, 5 * sizeof(int));  // 5個分に拡張(元の1,2,3は保たれる)
    if (arr == NULL) {
        printf("失敗\n");
        return 1;
    }
    arr[3] = 4;
    arr[4] = 5;

    int i, sum = 0;
    for (i = 0; i < 5; i++) {
        sum += arr[i];
    }
    printf("合計=%d\n", sum);

    free(arr);
    return 0;
}

realloc は「必ずしも同じ場所を拡張してくれる」わけではありません。空きが足りない場合は、内部で新しい場所にコピーしてから古い領域を解放し、新しいアドレスを返します。だから 必ず戻り値を受け取り直すarr = realloc(arr, ...))必要があります。

flowchart LR
  a["calloc(3, sizeof(int))<br/>0,0,0で確保"] --> b["1,2,3 を代入"]
  b --> c["realloc(arr, 5*sizeof(int))"]
  c --> d["1,2,3は保たれ<br/>4,5番目が使えるようになる"]
  c -.->|"空きが足りない場合"| e["別の場所にコピーして<br/>新しいアドレスを返す"]

やってみよう

realloc の拡張先のサイズをさらに大きくしてみたり、calloc で確保した直後に arr[0] を表示して 0 になっていることを確かめましょう(malloc だとゴミが入っている可能性があります)。

演習

calloc{10, 20, 30} の3要素を確保し、realloc で6要素に拡張してください。追加した3つの要素には 40, 50, 60 を入れ、6要素の合計を printf("合計=%d\n", sum); の形で表示してください(正しく書けると 合計=210 になります)。最後に free で解放してください。

ヒント1を見る

arr = realloc(arr, 6 * sizeof(int)); で6個分に拡張します。

ヒント2を見る

arr[3] = 40; arr[4] = 50; arr[5] = 60; を追加してから合計します。

実際に動かしてみよう

下のエディタにCを書いて「コンパイル & 実行」を押すと、ブラウザ内で本物のCコンパイラ(clang + dlmalloc)がその場でコンパイルして実行し、出力が表示されます。構造体・共用体・malloc/free・関数ポインタ・ファイル入出力などがそのまま動きます。本文の例を書き換えて試しながら進めましょう(初回だけコンパイラの読み込みに時間がかかります。以降はキャッシュされます。この回は標準入力(scanf)は使わず、値はコードに直接書きます)。

C/C++ — ブラウザ内で本物のコンパイラで実行

ブラウザ内で本物のC/C++コンパイラ(clang + libc++ / WebAssembly)を動かします。構造体・malloc/free・std::string・vector・クラス・テンプレート・STL などがそのまま実行できます(初回のみコンパイラの読み込みに時間がかかります。以降はブラウザにキャッシュされます)。
スクロールして表示された時点でも自動で読み込まれます。