動的メモリがオーバーフロー!ローカル変数での失敗


コンパイルは通ったのにプログラムの実行ができなかった話です。原因はローカル用の配列型変数が多すぎたことでした。

スポンサードリンク

ローカル変数の罠


*クリックで拡大

上図のように、clコマンド(コンパイル)は通ったのにexeファイルの実行には失敗する、という現象が発生しました。関数呼び出しから抜け出せない、所謂『無限ループ』の場合によく起こるエラーですが、今回はそのようなミスを書いたわけでもなく。プログラム的には間違っていないのに何故に…?と確認したところ、ソース内の以下の部分が原因だと判明しました。

int main(){
	int dat[640][480];//←ここ
	/*省略*/
	printf("\(^o^)/");
	return 0;
}

これを見て理解した方はブラウザバックして、どうぞ。

 

グローバル変数に移行

上のプログラムが実行できなかった原因は、int型の配列 dat が大きすぎたことにあります。640×480の2次元配列は、合計で307200個もの値をとってしまうため、オーバーフローを起こしてしまいました。

下記のように変更すれば万事解決です。

int dat[640][480];
int main(){
	/*省略*/
	printf("\(^o^)/");
	return 0;
}


*クリックで拡大

無事、プログラムの実行が完了です。

変数をmainの外に出しただけです。結局30万個以上の変数使ってますが、普通に実行できました。なんでですかね。

 

スポンサードリンク

記憶場所の違い

*クリックで拡大

main内で宣言した dat 配列ととmain外で宣言した dat 、何が違ったのでしょう。答えは、変数を記憶するメモリの場所です。

main内、つまり関数内で宣言された変数はローカル変数(その関数内でしか利用できない、関数終了時に破壊される(厳密にはポインタのみ破壊される))として扱われます。一方でmain外で宣言した場合は、グローバル変数(複数の関数間で利用できる、プログラム終了まで破壊されない)となります。この2つ、実は保存場所が違うのです。

ローカル変数動的メモリと呼ばれる部分に保存されます。このメモリは容量が控えめで、30万個ものint型変数を保存するのには適さないのです。

一方のグローバル変数静的メモリと呼ばれる部分に保存されます。こちらは30万個など余裕で保存してくれる包容力を備えています。

どうしてもローカル変数として使いたい場合は、malloc() などを使用して動的メモリの確保をする必要があります。使用後の開放も忘れずに。

 

おまけ:動的メモリチキンレース

#include <stdio.h>
#define MAX 260000 //←これ
int main(int argc, char *args[]){
	int dat[MAX];
	printf("\n%d\n",MAX);
	printf("\n\(^o^)/\n");
	return 0;
}

上のプログラムを使用して、動的メモリがどれだけのint型変数に耐えられるかの確認ができます。MAXの値を変更していき、\(^o^)/が表示されたら成功、プログラムが固まったら失敗です。チキンレースにも使えますが、くっそつまらんです。


*クリックで拡大

わがパソコンの限界はこちら。これから1増やしたら固まりやがりました。ご参考までに。

スポンサードリンク