スタック
公開日: 2025/06/02
スタックとは?──関数の実行とメモリ管理を支える“後入れ先出し”の基本構造
はじめに
関数を呼び出して戻る、変数を定義してスコープが終わったら消える…。
こうした動作の背後では「スタック(Stack)」という仕組みが働いています。
また、アルゴリズムやデータ構造の分野でも頻出する概念です。
本記事では、**スタックの仕組み、特徴、使いどころ、ヒープとの違い、バグの原因にもなる“スタックオーバーフロー”**までをわかりやすく解説します。
基本情報・概要
スタックとは、後から入れたものを先に取り出す「後入れ先出し(LIFO)」の構造を持つデータ構造/メモリ領域です。
関数呼び出しや一時的な変数の保存に用いられ、自動的な確保と解放が可能な軽量なメモリ管理機構として広く使われます。
主な用途:
- 関数の呼び出し・戻り時の情報保持
- 局所変数(ローカル変数)の一時的格納
- 式の評価や逆ポーランド記法の計算
- 再帰処理や戻り先の管理
スタックは「処理の“積み重ね”と“巻き戻し”を支える基本の箱」です。
比較・分類・特徴の表形式まとめ(任意)
メモリ領域 | 特徴 | 使用対象 |
---|---|---|
スタック | サイズ固定、高速、スコープ終了で自動解放 | 関数の実行情報・ローカル変数 |
ヒープ | サイズ可変、遅い、明示的な確保と解放が必要 | 動的メモリ、長期間使うデータ |
スタックは「短命かつ局所的な処理に特化した高速メモリ領域」です。
深掘り解説
✅ スタックの実際の動作(Cの例)
void hello() { int a = 42; // スタック上に確保 printf("%d\n", a); } int main() { hello(); // hello() のスタックフレームが push return 0; // 終了時に hello() のフレームが pop }
- 関数が呼ばれると「スタックフレーム」という領域が積まれる
- 関数が終わると自動で削除される(
)pop
- スレッドごとにスタックサイズが決まっており、超えるとスタックオーバーフローが発生
✅ スタックオーバーフローとは?
void recurse() { recurse(); // 無限再帰 } int main() { recurse(); // ⇒ Stack overflow! }
- 再帰処理や巨大なローカル配列などが原因
- プログラムがスタック領域の上限を超えるとクラッシュする
- 対策:再帰の深さ制限、ループへの置換、大きなデータはヒープへ
応用・発展的な使い方
-
アルゴリズムでのスタック利用
- 括弧の対応判定
- 深さ優先探索(DFS)
- Undo処理や戻るボタンの履歴
-
データ構造としてのスタック(LIFO)
で追加、push()
で取り出しpop()
- 実装は配列やリストで表現される
-
JavaScript のコールスタック
- 同期関数の呼び出しはすべてこの中で管理
- エラー時の「stack trace」もこの構造に基づく
よくある誤解と注意点(任意)
- スタックとキューを混同しないこと:キューは「先入れ先出し(FIFO)」
- ローカル変数は関数終了時に消える:返り値でしか外に渡せない
- スタック領域のサイズには限界がある:数百KB〜数MB程度(言語やOSによる)
- 大きな配列・構造体はヒープに逃がすのが安全
スタックは便利だが、「一時的な用途に限定することが安全設計の基本」です。
まとめ
スタックは、関数呼び出しや一時変数を効率よく扱うために最適化されたメモリ構造/データ構造です。
自動管理され、高速で安全な反面、容量に制限があり