問題の歴史:
スタックメモリはすべての主要なアーキテクチャに存在します。C言語では、オートマチック(ローカル)変数がスタックに配置され、動的ヒープと比較してメモリの割り当てと解放が高速度で行われます。
問題:
スタックのサイズには制限があり、オートマチック変数はブロックを出ると自動的に破棄され、スタックオーバーフローが発生するとプログラムがクラッシュしたりデータが破損したりします。
解決策:
特別な修飾子なしに関数内で宣言されたローカル変数はスタックに配置されます。この自動ストレージ領域は関数に入ると作成され、出ると破棄されます。スタックのサイズには制限があり、リンカ/システムのオプションでのみ変更できます。
コード例:
#include <stdio.h> void foo() { int arr[100]; // スタック上に配置 for (int i = 0; i < 100; ++i) arr[i] = i; printf("First element: %d\n", arr[0]); } // arrはfooを出ると破棄される
主な特徴:
関数からローカル変数をアドレスで返すことはできますか?
いいえ、変数は関数を出ると破棄されるため、結果的に「悬垂ポインタ」が生成され、未定義の動作を引き起こします。
int* bad() { int x = 42; return &x; // エラー: 返されたポインタは解放されたスタックを指します }
スタックに大きな配列(例えば1MB)を配置することは可能ですか?
ほとんどのシステムでスタックには限界があり(数十から数百KB)、巨大な配列をスタックに宣言しようとするとスタックオーバーフローが発生します。
スタティック変数とオートマチック変数の配置の違いは何ですか?
スタティック変数(関数内でも)は静的メモリ領域に配置され、呼び出しの間にクリアされず、オートマチック変数はスタック上に配置され、ブロックを出ると破棄されます。
計算を行う関数でスタック上に8192*1024のdouble配列を割り当てました。プログラムはLinuxで実行時にSIGSEGVを受け、コンパイルエラーはありませんでした。
利点:
欠点:
大きなバッファを扱うためにmalloc/freeを使用して動的メモリ割り当てを行いました。スタック上には小さな作業変数のみが配置されました。
利点:
欠点: