- ベストアンサー
C言語に詳しい方お願いします。break文によってループをどのように脱出できるのか等。
質問1.自分で簡単なプログラムを作ってみて簡単な実験をしてみたのですが,break;を使うとループをすべて抜けるのではなくいくつかループがある場合『一番内側のループを抜ける』ということでいいのでしょうか? 例えば do { }while() while(){ } for(i=0;i<N;i++) のループにはすべてbreak;は通じるのでしょうか?この他にbreak;が使えるループはありますか? 2.これも自分で試しに実験してみたのですが, #define R (double)rand()/32767.0 としておいて 例えば, a=sin(R); b=a; のように使用した場合, a=sin(R)の部分では乱数が新たな値に更新されるが, b=aの部分では乱数が新たな値に更新されない感じがします。 結論:Rが見える形で含まれていれば乱数の値は更新され,Rが見えない形で含まれていると乱数の値は更新されない。 ってことでしょうか? これは#defineの部分に何か秘密があるような気がします。詳しい方回答よろしくお願いします。
- みんなの回答 (9)
- 専門家の回答
質問者が選んだベストアンサー
質問1について。 >『一番内側のループを抜ける』ということでいいのでしょうか? その通りです。 breakは3種のループすべてに使えます。 C言語で使われる反復文(ループする命令)はその3種類だけです。 他に、反復文ではないけれど、switchでbreakが使えます。 3種の反復文の中とswitchの中以外ではbreakは使えません。 質問2について。 乱数が新たな値に更新されない、ということですが、 それが自然です。 「代入したのだから、変数b と sin((double)rand()/32767.0) は同じ」 と考えたのかもしれませんが、それは違います。 a=sin(R); の時点で、rand()で作られた乱数は、 ある数値となってaに格納されます。 aに格納された後は、単なる数値でしかありません。 bに代入するのはその値になります。 「Rを使うとその都度違う乱数が出てくるのに、 =による代入では違う」といったところで混乱が起きたのかもしれません。 #defineは、単なる「文字列の置き換え」です。 コンパイルの最初の方で展開されます。 だから sin(R); は sin((double)rand()/32767.0); とおきかえられます。 Rの出てくるところは、毎回、このように記述したのと同じなのです。
その他の回答 (8)
- shige_70
- ベストアンサー率17% (168/946)
gotoが大好きな者です。(笑) gotoは禁じ手なので使いたくないという向きであれば、たとえば while ( xxx ) { f = 0 ; while ( xxx ) { if ( xxx ) { f = 1 ; break ; } } if ( f ) { break ; } } のように工夫すればgotoなしで一気に抜けられます。 forなら外側のループカウンタをむりやり終了値にしてしまうなんてのもありです。 でも、こんなまどろっこしいことするなら素直にgoto使えといいたくなるかもしれませんけどね。 あとは、少々荒技なんですが、setjmp() と longjmp() というのを使うと豪快に飛べます。普通の参考書には載ってないでしょうけど。。。興味があったら調べてみてください。
お礼
回答ありがとうございます. setjmp()とlongjmp()なんてあるんですね.知りませんでした.説明してあるページを見つけて軽く読んだのですが,初心者の僕ではちょっと意味がよく分からんでしたf^^;
- z64423
- ベストアンサー率53% (26/49)
switch 文は continue で脱出して、すぐ外のループの条件判定まで飛べます。 この機能は便利ですよ。
お礼
回答ありがとうございます。 手元にあるC言語の入門書を読んでcontinueについて確認しました。使った事はないのですが,ifと組み合わせると便利そうですね。
1. 多重ループの場合は、禁じ手とされているgotoを使うのが便利。自分はコード効率の面で、多重ループを組む場合で最適化できないルーチンではgotoを使う。 switchはまぁ、Breakは使えるけど、使い方が相当異なるから何ともいえない。
お礼
回答ありがとうございます。 禁じ手のgotoもそういう用途があったのですね。
- JaritenCat
- ベストアンサー率37% (122/322)
breakは一番内側のブロックを抜けます。 do{}while(); while(){} for(){} switch(){case:} で使いますね。 rand関数は0からRAND_MAXまでの擬似乱数を返します。 #define R (double)rand()/32767.0 → 以降のR を (double)rand()/32767.0 に書き換えます。 a=sin(R) → a=sin((double)rand()/32767.0) と同じですね。 b=a → aをbに代入しただけなので、bはaと同じ値になり乱数は関係ありません。もう一度乱数が欲しければ b=sin(R)として下さい。
お礼
回答ありがとうございました。 >もう一度乱数が欲しければ b=sin(R)として下さい。 なるほどです。今まで曖昧だった理解が具体性を帯びてきました。
- επιστημη(@episteme)
- ベストアンサー率46% (546/1184)
Q1>『一番内側のループを抜ける』ということでいいのでしょうか? YES. (ループじゃないけど switchもbreakで抜けます) Q2. #define はただの'置き換え'です。 a=sin((double)rand()/32767.0); b=a; と書いたのと同じです。
お礼
ピンポイントに的をついた分かりやすい解説ありがとうございます。 #defineはただの置き換えと解釈すればよかったんですね。
- bonyamk
- ベストアンサー率29% (49/166)
breakの解釈はあってますね 「一番内側のループを抜ける」です for分の他は、、whileとか、do whileとか、、あとselectもその部類なのかな?(ループではないけどね) defineも解釈はあってます defineで置き換えられてるだけなので コンパイル時に a=sin(R); は a=sin((double)rand()/32767.0); としてコンパイルされます で、その結果をbに代入しているので bとaは常に同じになります
お礼
>あとselectもその部類なのかな? selectとはどういう機能を持ったものなのですか? >その結果をbに代入しているので 代入しているだけということなんですね。 回答ありがとうございました。
breakはそのbreakを含む一番内側のループを抜けます。 (どうしても複数のループを一度に抜けたい場合はgotoです) breakは3つのループ全てに使えます。 ループはその3つしかないので、breakが使えるループは他にはないです。 aには既にsin(R)の結果が入っているだけなので、それをbに代入しても変化はありません。 defineの動きは単純で置き換えをしているだけです。 一般的にはコンパイルする前に a=sin((double)rand()/32767.0); // <-R が置き換わってる b=a; という風にされた後にコンパイルされます。
お礼
回答ありがとうございます。 >(どうしても複数のループを一度に抜けたい場合は >gotoです) gotoなら一気に脱出できるのですね! >一般的にはコンパイルする前に >a=sin((double)rand()/32767.0); // <-R が置き換わ>ってる >b=a; >という風にされた後にコンパイルされます。 なるほどこのように解釈するのですね!
- Tacosan
- ベストアンサー率23% (3656/15482)
ちょっと調べればすぐわかるはずで, 実験するようなことじゃないと思うけど.... break は「自分を含む, 一番内側のループまたは switch から」脱出します. ループは for, while, do~while の 3種類. rand は呼出されるたびに新しい乱数を返す. だから呼出さなければ乱数は新しくならない. それだけ.
お礼
回答ありがとうございます。switchからも脱出できるのですね。 >ちょっと調べればすぐわかるはずで, 実験するような>ことじゃないと思うけど.... こういうのってどうやって調べるとよいのでしょうか?
お礼
>3種の反復文の中とswitchの中以外ではbreakは使えません。 ということはもしその中以外で使うとエラーになるということでしょうか?? >a=sin(R); >の時点で、rand()で作られた乱数は、 >ある数値となってaに格納されます。 >aに格納された後は、単なる数値でしかありません。 >bに代入するのはその値になります。 この説明なるほど納得です!!言われてみれば当たり前の事ですが,僕は今まで理解しているようで理解できていませんでした。もはやb=aのaはある確定した値にすぎないのですね!! とても素晴らしい回答ありがとうございました。