osio_sioの日記

自分用メモ

C++の配列宣言時のメモリ確保についてメモ

c++の配列を宣言した時のメモリについて把握していなかった部分でエラーが発生したのでメモ✍️

発生した問題

ある時、

int main() {
   ~略~
   long long dp[109][100009];
}

という感じでmain関数内でdpを宣言したところ、segmentation faultになってしまい、何が原因かよくわからなかったが、以下のようにグローバル変数として宣言すると直った。

long long dp[109][100009];
int main() {
   ~略~
}

原因

c++のメモリの確保方法が原因だった。

関数内(ローカル変数)で宣言するとその配列はスタック領域に確保されるらしい。スタックは通常、そのサイズが限定されており(多くのシステムで数MB程度)、大きな配列を配置しようとするとスタックオーバーフローを引き起こし、結果的にセグメンテーションフォールトが発生することがある。

一方で、同じ配列をグローバル変数として宣言する場合、この配列はプログラムのデータセグメントに確保される。データセグメントはスタックよりも大きな容量を持っており、さらに、オペレーティングシステムによって動的にサイズが拡張されることがある。そのため、大きな配列も安全に確保することができる。

セグメンテーションフォルトを防ぐ解決策

  1. 上に述べたように、グローバル変数として宣言する

  2. 動的メモリ割り当てを使用する。vectorを使用してヒープメモリに確保すれば、ヒープは使用可能なメモリ(物理メモリと仮想メモリの合計)内で拡張が可能であるため、非常に大きなデータ構造も扱うことができる。

おまけ(初期値について)

c++において初期値も、グローバル変数として宣言するときとローカル変数で宣言する時に違いがある。 結論から言うと、グローバル変数の場合は初期化されるが、ローカル変数で宣言した時は未定義の値を持つので、注意が必要。

int a[10];

int main() {
    cout << a[3];
}

出力結果:0

int main() {
    int a[10];
    cout << a[3];
}

出力結果:32759