• ベストアンサー

再帰呼び出しになってしまうのをループの形にしたい

VBで繰り返して実行するプログラムを作ったのですが、 スタック領域をオーバーしてしまいます。 再帰呼び出しになっているのはわかったのですが、 改善ができません。 簡略したら下記のような状態でした。 Sub test1()  test2 End Sub Sub test2()  test1 End Sub このtest1を実行して、繰り返し作動するようにしたのですが、 当然スタックオーバーフローになります。 簡単にループに変形できるのでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • AKARI0418
  • ベストアンサー率67% (112/166)
回答No.3

DO WHILE(条件) CALL test1() LOOP Sub test1() CALL test2 End Sub Sub test2() 処理 End sub でよいのではないでしょうか?

emson100
質問者

お礼

具体的なコードありがとうございます。 基本的に教えていただいたコードの流れで構築し、 Do untilで無限ループで実行することができました。

その他の回答 (3)

  • imogasi
  • ベストアンサー率27% (4737/17068)
回答No.4

文系(経理など)課題では余り出てこないことなので、自信はありませんが http://www2.cc.niigata-u.ac.jp/~takeuchi/tbasic/BackGround/Recursive.html を参考に言いますと 質問のTest2というような大雑束なプロシージャのことでなく、再帰をさせるコア処理のところに注目する必要が有ると思う。 下記は数の処理のようなことが多いので参考にしにくいかもしれないが Function Kaijyou(n) F = 1 For i = 1 To n F = F * i Next i Kaijyou = F End Function ーーーー Sub test01() MsgBox Kaijyou(5) End Sub ーーーー Function Fib(n) If ((n = 1) Or (n = 2)) Then Fib = 1 Else Fib = Fib(n - 1) + Fib(n - 2) End If End Function ーーーーー Sub test02() MsgBox Fib(8) End Sub ーーーーーー Function con(n) For i = 1 To n con = con & i Next i End Function ーーーー Sub test03() MsgBox con(8) End Sub のように (1)処理の中で、左辺に「代入される関数名が単独で」がありと、その右辺にも「関数名を使った加工式」がある。 これによって1段階前の状態と、現在の状態がつながる。 (2)無限ループにならないよう、合理的な終了条件が処理の中に かならず入っている。 この2条件を満たすように組めばよいと思う。 ただし上例のような1変数で数値を決める者でなく、文系の処理の場合は、どういう例なのか、何も言わないで質問者は>VBで繰り返して実行するプログラムを作ったのですが、といっていて良くわからない。 再帰にしないために下記にしてみた。 何かの参考になれば。 Public m Public m1, m2 を使って Function Kaijyou2(n) For i = 1 To n m = m * i Next i Kaijyou2 = m End Function ーーー Sub test011() m = 1 MsgBox Kaijyou2(6) End Sub ーーー Function Fib2(n) For i = 1 To n - 2 m = m1 + m2 m2 = m1 m1 = m Next i Fib2 = m End Function ーーー Sub test021() m1 = 1: m2 = 1 MsgBox Fib2(8) End Sub ーーー Function con2(n) For i = 1 To n m = m & i Next i con2 = m End Function ーーー Sub test031() MsgBox con2(8) End Sub

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.2

スタックオーバーフローするほど再帰するのは離脱条件が間違ってて無限再帰してるんじゃないかという気がしますが。 ループに置き換えることを考えるより先にそちらをチェックしてみては?

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.1

どのように実行したいのかを具体化しましょう お示しのソースではTest1/Test2をどのように実行したいのかが判断できません ある回数だけTest1/Test2を実行したい 条件が満たされるまでTest1もしくはTest2お実行したい ・・・ ある条件も提示 このTest1/Test2の他にMainループがあるのでしょうか

関連するQ&A

  • VC++ 再帰呼び出しについて

    VC++6.0にてプログラミングを行っているものですが、 関数の再帰呼び出しについて質問です。 再帰呼び出しの際にスタックに積まれる変数というのは、 再帰呼び出しをする関数に渡す引数のことですか? スタックオーバーフローを起こさないために、 staticなポインタにHeap領域上の 変数を割り当てるとよい。 と分かったのですが、 この意味は、例えば static int *a = new int; ということなのですか?

  • C# 再帰よるスタックオーバーフローについて

    VB2008 C# でプログラムしていますが、 プログラムで再帰を多く行わなくてはならず、 スタックオーバーフローが出てしまいます。 スタックオーバーフローを解決するためには、アルゴリズムを変更し、 再帰の回数を減らすしか方法はないのでしょうか? もしスタックの上限を変更する方法などがありましたら教えてください。 VBは初心者なので、なるべく簡単にお願いします。

  • 再帰関数を使うとき、ソフトウェアスタックはハードウェアスタックと比べてどれくらい遅い?

    再帰を使って関数を書こうと思うのですが、再帰する回数が不明なので、スタックオーバーフローを避けるためソフトウェアスタックを使おうと思っている者です。 ソフトウェアスタックはどれくらい遅いのでしょうか? どう実装すれば速度が改善されるのでしょうか?

  • 【C言語】再帰が時間がかかる理由について

    再帰のプログラムがなぜ時間がかかるのかを詳しく調べています。 アセンブリレベルで見ると、 callに時間がかかるのか?それともpop命令?それとも退避? 結局、よく分からないまま、 Google検索して調べています。(まだよくわかってません。) 再帰呼び出しのデメリットは、 スタック領域を大量に消費する、関数呼び出しのオーバーヘッドであること。 この事実はわかりました。 しかしながら、 オーバーヘッドとは具体的に何なのか これを調べています。 どなたか、良いサイト・書籍を知らないでしょうか。 教えてください。

  • OCXからのコールバックを繰り返すとスタック領域が不足する

    こんにちは。 いつもお世話になっております。 OCXからのコールバックが繰り返された場合に「実行時エラー28 スタック領域が不足しています。」が発生して困っています。 以下のようにOCXからのコールバックでプロシージャを再帰的に呼び出しています。 <Command1_Clickイベント> ------------------------------------------------------------------------------------- Private Sub Command1_Click() 'OnTestイベントを発生させる Test.Test End Sub ------------------------------------------------------------------------------------- <OnTestイベント> ------------------------------------------------------------------------------------- Private Sub Test_OnTest(ByVal sStatus As Long, ByVal FileName As String) Select Case sStatus Case 0 'ステータスが0になったら終了 Exit Sub Case Else '再帰的にOnTestイベントを発生させる Test.Test End Select End Sub ------------------------------------------------------------------------------------- すると、294回目でスタック領域不足が発生します。 MSDNによると「イベント連鎖」と呼ばれるものであるようですが、途中までうまくいくので何か他に原因がないかと思っています。 http://msdn2.microsoft.com/ja-JP/library/0ctsw64a.aspx 回避策などありましたらご教示下さい。 ちなみにOCXの処理としては、フォルダ内の該当ファイル名を1つずつ返すというものです。 <環境> Windows 2000, VB6.0

  • 再帰的(リカーシブ)プログラムの説明について。

    以下は、再帰的(リカーシブ)プログラムの説明を記載しました。 この説明文でおかしい箇所の添削をお願い出来ないでしょうか? 宜しくお願い致します。 以下からになります。 再帰的(リカーシブ)プログラムとは、プログラムの中から自分自身を呼び出して実行することを再帰的(リカーシブ)アルゴリズムといい、この形式で再帰呼び出しを行うプログラムのこと。 まずは、再帰的アルゴリズムについて、例を使って説明を行いたい。 主プログラムとサブルーチンaがある。 主プログラムは、文字通り、主(メイン)となるプログラム。 サブルーチンは、主プログラムが呼び出して利用する処理をひとまとめにしたもの。 文字通り、サブとなる処理を行う。 主プログラムには、CALL aという命令が記述されている。 これはサブルーチンaを読み出すという命令。 この再帰的プログラムは、処理が終わったら、読み出された場所に帰っていく。 このため、戻り場所を記憶しておかないと帰る事が出来ない。 この戻り場所を記憶するのが、LIFO方式による記憶領域になる。 LIFO方式の記憶領域だから、スタック領域になる。 スタック領域だから、後入れ先出しで戻り場所を記憶していく。 まずは、1回目の呼び出しとして、主プログラムがサブルーチンaを呼び出している。 1回目の戻り場所を記憶しておく。 次にサブルーチンaを見ると、CALL a、つまり自分自身を読み出している。 これが2回目の読み出し。 このように自分自身を呼び出すことを再帰呼び出しという。 同じプログラムの中で自分自身を読み出しているのだが、コンピューターは、あたかも別のサブルーチンがあるように処理が行われている。 この場合、それぞれの処理で、別の変数を用意しながら処理を行う。 このサブルーチンで処理が終わった場合にも、もとに戻る必要がある。 これは2回目の呼び出しになるため、2回目の戻り場所を記憶しておく。 更に、3回目として再びサブルーチンaを呼び出す。 3回目の戻り場所を記憶し、また別の変数を用意しながら処理を行う。 ここで最後のサブルーチンで処理が終わったとする。 処理が終わったら、呼び出された場所に戻る。 戻り場所の記憶を見てみると、上から戻る順番に記録されていることがわかる。 戻り場所はLIFO方式、後入先出しで記録されているから、最後に呼び出した3回目の戻り場所が1番上に記録され、次に2、最後に1が記録されている。 最初は戻り場所を記憶した記憶領域を参照して、3回目に呼び出された場所に戻る。 ここで3の戻り場所が消える。 そして引き続き処理が行われる。 次に、2回目に呼び出した処理が終わり、2回目に呼び出された場所に戻り、2の戻り場所が消える。 また引き続き処理が行われ、1回目に呼び出した処理が終わり、1回目に呼び出された場所(主プログラム)に戻り、1の戻り場所が消える。 そして処理が行われ、プログラム全体が終了する。 このように、プログラムの中で自分自身を呼び出し、戻り場所を記憶しながら実行するようなプログラムを再帰的(リカーシブ)プログラムという。

  • 組み合わせを抽出するために使う再帰呼び出しについて

    1,2,3,4,5の数列から3の数の組合せをワークシートに表示するプログラムを作っています。 このソースは以前他の質問に載っていたものを自分用に多少アレンジしたものです。構造は再帰呼び出しを使って、123、124、125、134、135、145、234、235…345という形で結果を出力します。いろいろと試してみて、計算結果は正しいとわかったのですが、デバックをしていて1つどうしても理解できないことがありました。計算結果が145から234になるとき、カーソルがSub combiPrのEnd subを指したあと直前のEnd ifに移ります。その後Forに移って234以降の計算を始めます。どうしてEnd Subからこのような動作をするのかわかる方いらっしゃいましたら是非ワケを教えてください。よろしくお願いしますm(_ _)m Const m As Integer = 3 '←取り出す個数 Const n As Integer = 5 '←サンプル数 Dim rStr As String Dim mRow As Integer Dim Nest As Integer Dim A(10) As Variant Sub combi() Cells.ClearContents mRow = 0 Nest = 0 combiPr (0) End Sub Sub combiPr(n1) Dim mCol As Integer For nn = n1 + 1 To n - m + Nest + 1 Nest = Nest + 1 A(Nest) = nn If Nest = m Then mRow = mRow + 1 For mCol = 1 To m Worksheets(1).Cells(mRow, mCol).Value = A(mCol) Next Else Call combiPr(nn) End If Nest = Nest - 1 Next nn End sub

  • 関数呼び出しでのスタック消費量

    C++で関数を再帰呼び出しするとスタックオーバーフローとなりました。 それで、どれ位なら可能か調べるため、次の関数で試してみました。 int null(void) {  int a;  return null(); } 結果は次の通りでした。 1回目 &a 0x001cf9d4 2回目 &a 0x001cf8f4 3回目 &a 0x001cf814 よって、一回の呼び出しでスタックをe0(224)バイト使用してるようです。 なぜ(何に)こんなにも多く使うのでしょうか? 環境は、Vista Home Premium、Microsoft Visual C++ 2010 Express です。

  • 最大スタックサイズを大きくすることの影響は?

    再帰呼び出しを行うプログラムでスタックオーバーフローが発生するようになりました。 そこで最大スタックサイズを変更しようと考えていますが 最大スタックサイズを大きくすることで何か影響があることはあるのでしょうか? 他アプリ等に影響が出ないかを懸念しています。 ※最大スタックサイズは最大で16Mらしく、現在は1Mです。  特に影響がないのであれば最初から16Mにしておけば良いような気もして疑問に思っています。

  • VBで無限?ループからスタックオーバ

    VisialBasicで、デバッグ中にスタックオーバでプログラムが異常終了しました。呼出履歴をみると  ある関数→非Basicコード→  同じ関数→非Basicコード→  同じ関数→非Basicコード→ と連続している様です。 関数はイベントプロシージャ(_selChange)ですが、 プロシージャの途中で非Basicコードを呼んでる様です。(ステップ実行でも同じ。) VB初心者ですが、原因が全く解りません。 どなたか思い当たる人はいませんか?

専門家に質問してみよう