- 締切済み
do-while文の処理が実行されない
コンパイラは通ったのですが、自分の思うように処理されない箇所があって困っています。 1区間の数字列を回帰直線で近似し、回帰直線との誤差が最大の点で区間を分割(誤差が閾値以上なら)するプログラムを作っています。次に分割した区間それぞれに同様の作業をし、分割が一つでもあればまた最初から繰り返す、どこも分割されなければ終了・・・という流れです。 プログラムでは do{ bunkatu=0; for(全ての区間){ (最大誤差や回帰直線の傾きを0に初期化する) (傾き、最大誤差求める) if(最大誤差が閾値以上なら){ (最大誤差の点を境に区間を分けるよう設定) bunkatu = 1;} } }while((bunkatu) != 0); と表しています。分割が一つでもあれば変数 bunkatu が1になり、whileの条件 (bunkatu) != 0 と合っているのでまた do 以下から動作する・・・と考えているのですが、考え方としてはこれで合っているのでしょうか。
- みんなの回答 (5)
- 専門家の回答
みんなの回答
- 和泉 博(@hiroshi09s)
- ベストアンサー率54% (59/109)
#1さんの質問に『調べたところ回数が延々と出力され、10数万いったぐらいで「セグメントエラー」が起こりプログラムが終了しました。for文から抜け出していないと思われますが、どうしてそうなるかが検討がつかない状態です。』と返答されているので、#4さんが回答しておられるように、設定配列要素数より大きな値(あるいは小さな値)をもって配列をアクセスしたことによるセグメンテーション違反のエラーです。 しかし、提示されたプログラムにそのような配列要素を変えるようなプログラム箇所はありません。すなわち、Kaikia(), Kaikib(), Gosa(), Point() のいずれかに配列要素を換えるようなプログラム部分を持っているものと思われます。そのプログラムの配列要素を決めるやり方をしている関数とその箇所を見つけて訂正して下さい。考えられるのは i=(int)実数計算式 をもって int型の配列要素としているアルゴリズムを使っている場合です。 なお、近似プログラムにおいて10数万も繰り返すことは、解のない発散状態にあることを示しています。よって、アルゴリズムの見直しも必要と考えます。
- 6yemon
- ベストアンサー率69% (25/36)
> 調べたところ回数が延々と出力され、10数万いったぐらいで「セグメントエラー」が起こりプログラムが終了 はっきり言って、これはまともな動作ではありませんので、どこかでメモリ破壊を起こしていると推測します。 メモリ破壊とは何か。 int a[5]; と定義した配列があるとします。この配列には a[0]~a[4] が存在しますが、a[5] = 0; とすれば、この配列以外のメモリを書き変えてしまうことになります。Cは配列の上限チェックを行いません(下限もチェックしない)ので、意図したか否かに関わらず、配列以外のメモリを書き変えることができてしまいます(いわゆるバッファオーバーフロー)。そのメモリは別の変数である可能性大ですから、プログラムの記述とは違う時点でその変数の値が変わってしまいます。こうした事を「メモリ破壊」と呼びます。メモリ破壊があれば、プログラムが思いもよらぬ動きをするのは当然です。 char の変数領域(8bit単位)に int 型(32bitの事が多い)へのポインタで書き込む、int の変数領域に double 型(普通64bit)へのポインタで値を書き込む…等もメモリ破壊を起こします。他に、スタックオーバーフローを起こした、割込処理或いは他のスレッドによって変数が書き変えられた等、いろいろなケースがあります。 大抵の場合、メモリ破壊はプログラムのバグであり、それがどこに潜んでいるか簡単に見当がつくようなものではありませんが、バグがあるかもしれないという目で提示されたコードを眺めてみると、気になる所がいくつかあります。特に for 文の回し方がそうです。 例えば、次の for 文。 for (o = all; o >= 0; o--) { ... 上記の int a[5]; について for ループを回すとしたら、例えば for (o = 4; o >= 0; o--) { a[o] = 何か; } のように回すことができますが、配列のサイズが5だからと言って for (o = 5; o >= 0; o--) { a[o] = 何か; } と回したなら、本来存在しないはずの a[5] を書き変えてしまいます。これを連想してしまうのです。要するにバッファオーバーフローです。 他にも ・E[h] = E[h - 1]; の E[h - 1] が配列の外(E[-1])をアクセスする事はないか ・E[o + 1] = E[o]; の E[o + 1] は大丈夫か、等々 念のために言えば、これらが誤りだと断定しているのではありません。提示されたコードはプログラムのほんの一部分でしかなく、ここに至るまでの経緯がわかりませんから、この回し方で正しいかもしれませんし、もちろん他のコードがメモリを破壊している可能性もあります。疑いの目で見ないとバグの手がかりは得られないという事なのです。
- ricardo_
- ベストアンサー率19% (14/72)
bunkatu=0; のような初期化をループの中で行ったため、値が毎回リセットされループの脱出条件がいつまでも満足しないと言うようなミスを犯しやすい。 doやforループにそのような事がないか点検してみたらどうですか。 符号無し整数なのに負数になったら脱出というミスも有ります。 命令を削って無限ループの原因を探る事です。
- asuncion
- ベストアンサー率33% (2127/6289)
可能な限り、「ソースそのもの」を提示するようにしてください。
- ricardo_
- ベストアンサー率19% (14/72)
for文が for(;;){}; の形になっていないような感じがします。 for文の中で止まっているんじゃないかな。 printf("コメント") をプログラムの要所要所に入れ、プログラムが何処を通過するか調べたらどうですか。
補足
調べたところ回数が延々と出力され、10数万いったぐらいで「セグメントエラー」が起こりプログラムが終了しました。for文から抜け出していないと思われますが、どうしてそうなるかが検討がつかない状態です。
補足
do{ bunkatu=0; all=kaisuu; for(o=all; o>=0; o--){ katamuki=0.0; seppen=0.0; point=0; maxgosa=0.0; katamuki = Kaikia(S[o],E[o],x); seppen = Kaikib(S[o],E[o],x); if(E[o]-S[o] > 21){ maxgosa = Gosa(S[o],E[o],katamuki,seppen,x); if (maxgosa > 50.0){ point = Point(S[o],E[o],katamuki,seppen,x); for(h=all; h>=o; h--){ if(h>o){ E[h]=E[h-1]; S[h]=s[h-1]; } } E[o+1]=E[o]; E[o] = point; S[o+1] = point + 1; kaisuu++; printf("%d\n",kaisuu); bunkatu = 1;} } } }while((bunkatu) != 0); 失礼しました、上が自分のプログラムの質問部分のソースです。 Kaikia : 回帰直線の傾きを出力 Kaikib : 回帰直線の切片を出力 S(tart)[o],E(nd)[o] : 区間の始点と終点の位置 Gosa : 回帰直線と各点の最大誤差を出力 Point : 最大誤差を取る点の位置を出力 S[0]・・・E[0] S[1]・・・・・・・E[1] S[2]・・・E[2] という区間がある場合、S[1]とE[1]の間で分割が起こると S[0]・・・E[0] S[1]・ E[1] S[2]・E[2] S[3]・・・E[3] となるようプログラムしたものです。