
C言語入門|malloc と free による動的メモリ管理
ここまでで、
「スタック上の配列にはサイズと寿命の限界がある」
という事実を学びました。
じゃあ、
関数を越えて使える配列や
実行時にサイズが決まる配列
は、どうやって扱えばいいのでしょうか?
そこで登場するのが、
C言語における 動的メモリ管理 の主役、
malloc と free
です。
この2つを正しく使えるようになると、
C言語で扱えるデータの自由度が一気に広がります。

ヒープ領域を使うという発想
malloc が確保するメモリは、
これまで使ってきたスタック領域ではありません。
スタックとヒープの違い(おさらい)
| 項目 | スタック | ヒープ |
|---|---|---|
| 確保タイミング | 関数開始時 | 実行中に任意 |
| 解放タイミング | 関数終了時 | 明示的に解放 |
| サイズ | 小さい | 比較的大きい |
| 管理 | 自動 | プログラマ |
malloc は、
ヒープ領域に連続したメモリ領域を確保する命令
です。
malloc ― ヒープにメモリを確保する
まずは基本となる関数から見ていきましょう。
malloc の書式
void* malloc(size_t len);引数と戻り値
| 項目 | 内容 |
|---|---|
| len | 確保したいバイト数 |
| 戻り値 | 確保された領域の先頭アドレス |
| 失敗時 | ヌルポインタ |
malloc は、
- 「int を何個」
ではなく - 「何バイト」
を指定してメモリを確保する点が重要です。
malloc が返すポインタの正体
malloc の戻り値は void* 型です。
これは、
どんな型としても使える汎用ポインタ
という意味を持っています。
実際の利用では、
用途に応じて int* や char* にキャストして使います。
int* p = (int*) malloc(4 * 10);malloc だけでは終われない理由
ここで、とても大事なルールがあります。
malloc を使ったら、必ず free を使う
通常の配列は、
関数が終わると自動的に寿命が尽きます。
しかし、
malloc で確保したヒープ領域は 自動では解放されません。
free ― ヒープ領域を解放する
使い終わったヒープ領域は、
必ず free で解放します。
free の書式
void free(void* p);引数
| 項目 | 内容 |
|---|---|
| p | 過去に malloc で確保した先頭アドレス |
free を呼び出すことで、
- ヒープ領域が解放され
- 再利用可能な状態
になります。
解放し忘れるとどうなる?
free を忘れると、
確保したメモリは 永遠に使われたまま になります。
これを メモリリーク と呼びます。
メモリリークの影響
- プログラムが長時間動くほど
- 使用メモリが増え続け
- 最終的に異常終了
サーバプログラムや常駐アプリでは、
致命的な問題になります。
ヒープを使った安全な配列生成例
先ほどの「危険な配列返却」を、
ヒープを使って書き直してみましょう。
サンプルプログラム
プロジェクト名:10-10-1 ソースファイル名: sample10-10-1.c
#include <stdio.h>
#include <stdlib.h>
int* createScores(void)
{
int* scores = (int*) malloc(4 * sizeof(int));
return scores;
}
int main(void)
{
int* p = createScores();
if (p == NULL) {
printf("メモリ確保に失敗しました\n");
return 1;
}
p[0] = 75;
printf("確保したアドレスは %p です\n", p);
free(p); // 使い終わったら必ず解放
return 0;
}実行結果(例)
確保したアドレスは 0x55b1c8f2a2a0 ですなぜヌルポインタを確認するのか
malloc は、
メモリ確保に失敗すると ヌルポインタ を返します。
ヌルポインタとは
- アドレス 0 を指す特別なポインタ
- 「何も指していない」ことを表す
C言語では伝統的に、
- NULL
- (void*)0
が使われてきました。
近年の C23 以降では、
nullptr の利用が推奨されています。
ここで押さえておきたい nullptr の正体
nullptr は、
「何も指していない」ことを表す特別なポインタ値です。
- アドレスの 0 番地を指すポインタ
- メモリ確保の失敗を表すために使われる
- 「有効なメモリではない」ことを示す合図
なぜ nullptr が推奨されるのか
従来の NULL は、
- 単なる整数 0 と区別がつきにくい
- 文脈によって意味が曖昧になる
という問題がありました。
そのため C23 以降のC言語 では、
ポインタ専用の値として nullptr を使う
ことが推奨されています。
0番地が特別扱いされる理由
コンピュータの世界では、
アドレス0付近は、どんな用途にも使わない
という暗黙のルールがあります。
そのため、
- malloc が有効なメモリを返す
→ 0番地になることはない - 0 が返る
→ 確保失敗
と判断できるわけです。
calloc という選択肢もある
malloc によく似た関数として、
calloc があります。
calloc の特徴
- malloc とほぼ同じ用途
- 確保直後に、全バイトを 0 で初期化
つまり、
- malloc + memset(0)
を - 1行で済ませたもの
と考えると分かりやすいです。
プロジェクトによっては、
- 安全性を重視して
- malloc を禁止し
- 常に calloc を使う
というルールが設けられることもあります。
動的メモリ管理で一番大切な考え方
malloc と free を使うとき、
一番大切なのは次の意識です。
確保した人が、必ず解放する
これを守れないと、
- メモリリーク
- ダングリングポインタ
→メモリを解放した後も、その解放されたメモリ領域を指し続けている「宙ぶらりん」の状態のポインタ - 二重解放
といった、深刻なバグにつながります。
まとめ:malloc と free は力を与える道具
malloc と free は、
- 配列の限界を超える。
- プログラムを柔軟にする。
非常に強力な道具です。
その一方で、
- 自動では守ってくれない。
- すべて自己責任
という、C言語らしい厳しさも持っています。
ここを乗り越えれば、
C言語の核心に一歩踏み込んだ
と言ってもいいでしょう。
