
C言語入門|配列の限界とヒープ利用の必要性
以下は、ご指定どおり ホームページ掲載用の記事本文 です。
章立てはせず、見出しのみを使って構成し、文調は親しみやすくフレンドリーでやわらかくしています。
サンプルプログラムは 内容を類似させつつ差し替え、表示メッセージも変更しています。
ここまでで、配列やポインタをかなり自由に扱えるようになってきましたね。
「配列って便利だなぁ」「もう何でも作れそう!」
そんな気分になっている頃かもしれません。
でも実は、普通の配列には超えられない限界があります。
そしてこの限界に気づかないまま使い続けると、
C言語で最も危険な不具合に直結してしまいます。
今回はその限界をしっかり理解したうえで、
なぜヒープ領域を使う必要があるのかを見ていきましょう。

「普通の配列」が持つ2つの限界
まず、結論から整理します。
関数の中で宣言する普通の配列には、次の2つの大きな限界があります。
配列の限界その1
大きな領域を確保できない
配列の限界その2
関数が終了すると寿命が尽きる
どちらも、
「配列そのものが悪い」わけではありません。
原因は、どこに確保されているかにあります。
配列はスタック領域に確保される
通常、次のように宣言した配列は、
void func(void)
{
int data[100];
}スタック領域 に確保されます。
スタック領域は、
- 関数が使う一時的な作業場所
- 関数の呼び出しと終了に合わせて
自動的に確保・解放される
という特徴を持っています。
スタック領域は意外と小さい
ここが最初の落とし穴です。
たとえ、
- PC全体のメモリが数GBあっても
- スタックとして使える領域は数MB程度
という環境がほとんどです。
何が起きるかというと…
int huge[100000];こうした大きなサイズの配列をいくつも、うっかり宣言すると、
- スタック領域があふれる
- プログラムが即座に異常終了
という スタックオーバーフロー が発生します。
つまり、
配列のサイズは「メモリ全体」ではなく
「スタックの容量」に縛られている
というわけです。
関数が終わると配列は消える
次に、もう一つの限界です。
スタック領域の最大の特徴は、
関数が終わると、確保された領域は無効になる
という点です。
これを理解していないと、
C言語で最も怖いバグに遭遇します。
危険な例:配列を返す関数
次のコードを見てください。
プロジェクト名:10-9-1 ソースファイル名: sample10-9-1.c
#include <stdio.h>
int* createScores(void)
{
int scores[4]; // 仮に2000~2015番地
return scores; // 先頭アドレスを返す
} // ← ここで scores の寿命は終了
int main(void)
{
int* p = createScores();
p[0] = 90; // もう使えない領域に書き込み!
return 0;
}一見すると、
「配列を作って、その先頭アドレスを返している」
ように見えます。
でも実際には、
関数が終了した瞬間に scores は消滅しています。
何がそんなに危険なのか
ポイントはここです。
- メモリはすでに解放されている。
- でも、アドレス値だけは残っている。
そのため、
- アクセスできてしまう。
- エラーも出ない
- たまたま動くこともある。
という、最悪の状態になります。
これは、
「もう存在しないものを指しているポインタ」
であり、
ダングリングポインタ と呼ばれます。
なぜC言語は止めてくれないのか
ここで改めて、C言語の性格を思い出しましょう。
- C言語は実行時チェックをほとんどしない
- メモリ管理はすべてプログラマの責任
つまり、
危険なことができる
でも止めてはくれない
という言語です。
このコードも、
- コンパイルは通る。
- 実行もできる。
- でも動作は未定義
という、非常に危険な状態です。
配列の限界を超えるために必要なもの
ここまでの話をまとめます。
スタック上の配列の問題点
| 問題 | 内容 |
|---|---|
| サイズ制限 | 大きな配列を確保できない。 |
| 寿命 | 関数終了と同時に消える。 |
これらの問題を解決するために必要なのが、
ヒープ領域の利用
です。
ヒープ領域とは何か(次の記事への導入)
ヒープ領域は、
- 必要なサイズを
- 必要なタイミングで確保でき
- プログラマが明示的に解放する
という、スタックとは正反対の性質を持っています。
ヒープを使えば、
- 大きな配列を安全に確保できる。
- 関数をまたいでデータを保持できる。
ようになります。
ここで覚えておきたい感覚
この章で一番大事なのは、次の感覚です。
配列そのものが悪いのではない
どこに、どの寿命で置かれているかが重要
「この配列はいつまで生きているのか?」
これを常に意識できるようになると、
あなたはもう C言語中級者の入口 に立っています。
