[C言語のはじめ方] Part25: 動的メモリ確保(malloc, calloc, realloc)

これまでのステップでは、プログラムの開始時に確保されるメモリ(静的メモリ確保)を中心に学んできました。しかし、プログラムを実行している途中で必要なメモリサイズが決まる場合や、実行状況によって必要なメモリ量が変わる場合には、静的メモリ確保だけでは対応が難しいことがあります 。

そこで登場するのが動的メモリ確保です!これは、プログラムの実行中に必要な量のメモリを確保したり、不要になったメモリを解放したりする仕組みです。C言語では、主にmalloccallocreallocという標準ライブラリ関数を使って動的メモリ確保を行います。これらの関数は <stdlib.h> ヘッダファイルで定義されています。

動的に確保されたメモリは、自動的には解放されません。不要になったら必ず free() 関数を使って解放する必要があります。これを忘れるとメモリリークの原因となり、プログラムがメモリを使い果たしてしまう可能性があります 。

1. malloc: メモリを確保する基本関数

malloc (memory allocation)

malloc関数は、指定されたバイト数のメモリブロックをヒープ領域と呼ばれるメモリ空間に確保します。確保されたメモリ領域の先頭アドレスをvoid*型のポインタとして返します。
#include <stdlib.h>
void* malloc(size_t size);
  • size: 確保したいメモリのバイト数。通常、sizeof演算子を使って必要なサイズを指定します。
  • 戻り値: 確保されたメモリ領域の先頭アドレス (void*型)。確保に失敗した場合はNULLポインタを返します。

mallocが返すポインタはvoid*型なので、実際に使用する際には目的のデータ型へのキャスト(型変換)が必要です。

注意点:
  • 確保されたメモリの内容は初期化されません(不定な値が入っています)。
  • メモリ確保に失敗するとNULLを返すため、必ず戻り値をチェックしましょう。
使用例:
#include <stdio.h>
#include <stdlib.h>
int main() { int *ptr; int n = 5; // 例えば、整数5個分のメモリを確保 // int型5個分のメモリを確保 (sizeof(int) * 5 バイト) ptr = (int*)malloc(n * sizeof(int)); // メモリ確保が成功したかチェック if (ptr == NULL) { fprintf(stderr, "メモリの確保に失敗しました。\n"); return 1; // エラー終了 } printf("メモリ確保成功!アドレス: %p\n", (void*)ptr); // 確保したメモリに値を代入 for (int i = 0; i < n; ++i) { ptr[i] = i * 10; printf("ptr[%d] = %d\n", i, ptr[i]); } // ★重要: 不要になったメモリを解放 free(ptr); printf("メモリを解放しました。\n"); return 0;
}

2. calloc: 初期化されたメモリを確保する関数

calloc (contiguous allocation)

calloc関数もメモリを確保する関数ですが、mallocとは少し異なります。指定された要素数要素ごとのサイズに基づいてメモリを確保し、その領域全体をゼロ(0)で初期化します 。配列のように、同じサイズの要素を複数確保する場合に便利です。
#include <stdlib.h>
void* calloc(size_t nmemb, size_t size);
  • nmemb: 確保したい要素の数。
  • size: 各要素のサイズ(バイト単位)。
  • 戻り値: 確保・初期化されたメモリ領域の先頭アドレス (void*型)。確保に失敗した場合はNULLポインタを返します。

mallocと同様に、戻り値は適切な型にキャストして使用します。

注意点:
  • メモリ確保に失敗するとNULLを返すため、必ず戻り値をチェックしましょう。
  • mallocと異なり、確保したメモリ領域は自動的に0で初期化されます。
  • 初期化処理が入るため、mallocより若干遅くなる可能性があります。
使用例:
#include <stdio.h>
#include <stdlib.h>
int main() { int *ptr; int n = 5; // 例えば、整数5個分のメモリを確保 // int型5個分のメモリを確保し、0で初期化 ptr = (int*)calloc(n, sizeof(int)); // メモリ確保が成功したかチェック if (ptr == NULL) { fprintf(stderr, "メモリの確保に失敗しました。\n"); return 1; // エラー終了 } printf("メモリ確保成功(初期化済み)!アドレス: %p\n", (void*)ptr); // 確保したメモリの内容を確認(すべて0のはず) for (int i = 0; i < n; ++i) { printf("ptr[%d] = %d\n", i, ptr[i]); } // ★重要: 不要になったメモリを解放 free(ptr); printf("メモリを解放しました。\n"); return 0;
}

3. realloc: 確保済みのメモリサイズを変更する関数

4. まとめと使い分け

malloc, calloc, reallocは、状況に応じて柔軟なメモリ管理を可能にする強力なツールです 。それぞれの特徴を理解し、適切に使い分けることが重要です。

関数主な用途初期化引数注意点
malloc指定バイト数のメモリ確保しない確保する合計バイト数内容は不定値。NULLチェック必須。
calloc配列など、複数要素のメモリ確保する (0で初期化)要素数、要素1つのサイズ初期化が必要な場合に便利。NULLチェック必須。
realloc確保済みメモリのサイズ変更しない(拡張部分)元のポインタ、新しい合計バイト数アドレスが変わる可能性あり。失敗時のNULLチェックと元のポインタの扱い(一時変数で受ける)。

これらの関数を使う上で最も重要なことは、確保したメモリは必ずfree()で解放することです。動的メモリ確保は非常に便利ですが、使い方を誤るとメモリリークや不正アクセスといった深刻なバグの原因となります。次のステップでは、メモリ解放free()について詳しく学びます。

参考情報

より詳しい情報や関数の仕様については、以下のリファレンスサイトなどを参照してください。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です