以下のサイトでC言語の勉強をしているのですが、このサイトのソースコードをコピペして実行してみたら上手くいきませんでした。
http://wisdom.sakura.ne.jp/programming/c/c30.html
==========================
#include<stdio.h>
void func(int );
int main() {
func(0);
printf("プログラムを終了します");
return 0;
}
void func(int max) {
if (max <= 10000) {
printf("%d\r",max);
func(max + 1);
}
}
==========================
実行してみると、何故か4700~4800の辺りで止まってエラーになってしまいます。
どうしてエラーになるのでしょうか?
No.4ベストアンサー
- 回答日時:
一言で言えば「スタックが溢れた」と思われます。
一般的に、C言語プログラムの関数呼び出しは、次のような処理によって実現されます。
(1)次のようなデータを、「スタック」と呼ばれるメモリ領域に保存
・呼び出し先の関数の処理が完了した後に、戻ってくるべき場所(アドレス、といいます)
・呼び出し先の関数に渡す引数値(この例では、maxなどが、それに相当)
(2)呼び出し先の関数の中で新たに変数などを使う場合は、そのための領域をスタックに追加確保(今回の例では、これはありませんが)
(3)呼び出し先の関数の処理を実行
(4)関数の処理が終わったら、(1)(2)で確保したスタックのメモリ領域を解放して、(1)で保存された場所に処理を戻す
(正確には他にもありますが、割愛します)
今回の例では、再帰呼び出しが行われているので(4)まで終わる前に、新たに(1)からの処理が追加で行われ、再帰が深くなるにつれて、次第にスタックが消費されて行きます。
スタックが無尽蔵にあれば、再帰が10001段(で、あってるかな)になるまで(1)から(3)が繰り返され、最終的に今度は関数の再帰処理が一段ずつ終了していくため、(4)が繰り返されます。
ところが、再帰が深くなっていく途中でスタックが尽きてしまうと、そこでスタックメモリ領域が溢れてしまい、そこから先が正常に動作を続けられなくなってしまいます。
スタックメモリがどの程度確保されるかは、環境によりけりで、ソースコードをコンパイルする際のオプション等で指定できる場合もありますが、いずれにしても、10000段もの再帰をするようなプログラムは、こういった実行環境の特性を踏まえていない、不適切な再帰の使い方だと思います。
このように、極端に深い再帰を何も考えずにするようなプログラミングは、悪い見本なので、真似をしないことをおすすめします。
関数の再帰的処理ってスタックを用いてたのですね。
再帰的処理にそのような問題があったとは驚きです。
こういう処理はなるべく避けるように気を付けたいと思います。
回答ありがとうございました。
No.6
- 回答日時:
スタックオーバーフローだと思うけど、printf関数の呼び過ぎで引っ掛かっている可能性もあるね。
まずはosにもよるけどprintf("%d\r",max);の¥rを¥nで実行してみてね。
ダメなら次はprintfを移動させてみてね。
void func(int max) {
if (max <= 10000) {
func(max + 1);
printf("%d\r",max);
}
}
10000まで実行してから帰りに減算しながら数値表示になるよ。
10000の表示まで行ったらスタックはokかも。
No.5
- 回答日時:
追記:
>このように、極端に深い再帰を何も考えずにするようなプログラミングは、悪い見本なので、真似をしないことをおすすめします。
十分なスタックを確保できることが事前にわかっていて、深い再帰をするアルゴリズムに必然性があるなど、十分に考慮した上での場合は、(「何も考えずに」ではないですし)この限りではありません。
補足ありがとうございました。
深い再帰をする必要のある状況があるかどうかは分かりませんが、再帰的処理の問題点は頭の片隅に入れておきます。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# Cのオブジェクトファイルの逆アセンブル 5 2023/05/13 01:51
- C言語・C++・C# c言語でユーザ関数を利用して複素数のべき乗と絶対値の数列を計算するプログラムが作りたいです。 3 2023/01/29 22:13
- C言語・C++・C# プログラミングペーパーテスト 次の問題の実行結果を答えろ #include int x[ ] = { 1 2022/06/16 21:49
- C言語・C++・C# プログラミングを教えて欲しいです。 配列aは、int a[9]={7,6,12,8,3,5,10,9 4 2022/12/19 23:27
- C言語・C++・C# C言語 プログラミング 4 2022/05/22 11:53
- C言語・C++・C# C言語 3 2022/10/04 15:07
- C言語・C++・C# プログラムの時、フローチャートはどうなりますか?図でお願いします。 int main(void) { 1 2022/10/01 22:45
- C言語・C++・C# C言語でif文が予想と違う動きをする件について7 4 2023/03/20 00:26
- C言語・C++・C# プログラミングの授業のペーパーテスト 実行結果を答えろ #include int x[ ] = {1 3 2022/06/16 20:08
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
VBAの配列サイズとメモリに関して
-
動的メモリとexit(C言語)
-
C言語で、メモリを解放しないで...
-
【C言語】再帰が時間がかかる...
-
メモリ不足
-
バッチファイルでの実行EXEのメ...
-
クイックソート
-
C,C++プログラムの強制終了時の...
-
malloc関数の使い終わった後の...
-
プログラム開発勉強専門のPC...
-
JavaのStringの最大文字列長
-
メモリーリークエラーが起こる
-
メモリの解放の仕方
-
メモリの消費量について
-
VBAで2進数を返すプログラムの...
-
VC++におけるメモリ使用量について
-
ゲームプログラミングのマップ...
-
シェル(perl)が使用するメモリ...
-
値のコピーについて
-
メモリのセグメント違反の解決...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語で、メモリを解放しないで...
-
VBAの配列サイズとメモリに関して
-
エクセルのメモリ使用状況/Appl...
-
sil_rew_memのメモリアクセスに...
-
メモリのセグメント違反の解決...
-
EXCEL-VBAにてADOのレコードセ...
-
C言語における再帰呼び出しの...
-
メモリが不足しています(VBA)
-
【C言語】再帰が時間がかかる...
-
メモリアロケーション異常の発...
-
エクセル キャッシュメモリー...
-
大容量のメモリ確保をスワップ...
-
ファイルマッピング関数で失敗
-
バッチファイルでの実行EXEのメ...
-
動的メモリとexit(C言語)
-
メモリ不足
-
「ヒープサイズの設定」て何?
-
「memcpy」と「strcpy」について
-
LoadLibraryしたらFreeLibrary
-
C言語初心者です。debug assert...
おすすめ情報