ページ 11

switchでループを抜ける方法

Posted: 2013年7月28日(日) 17:58
by Lawliet
例えばwhile文で無限ループをしている時にif文でbreakすれば抜けられますが、
switch文をつかったときはbreakでも抜けられないですよね。

そんな時はフラグを使うなんていう手も思いつきますが
みなさんはこういう時には他にどういう手段を持って乗り越えていますか?

Re: switchでループを抜ける方法

Posted: 2013年7月28日(日) 18:23
by みけCAT
言語が指定されていませんね。
Javaなら抜けたいwhile文の前に"ラベル名:"と書いておき、その中で"break さっきのラベル名;"と書くと、
「抜けたいwhile文」を抜けられます。

コード:

import java.util.*;
import java.lang.*;

class Main
{
    public static void main (String[] args) throws java.lang.Exception
    {
        int i=0;
        hoge: while(true) {
            switch(i) {
                case 0:
                    System.out.println("Ishida Akira");
                    break;
                case 1:
                    System.out.println("Miyata Koki");
                    break;
                case 2:
                    System.out.println("Yamaguchi Kape");
                    break;
                case 3:
                    System.out.println("Toriumi Kosuke");
                    break;
                case 4:
                    System.out.println("Sawashiro Miyuki");
                    break;
                case 5:
                    System.out.println("Ogata Megumi");
                    break;
                default:
                    break hoge;
            }
            i++;
        }
    }
}

Re: switchでループを抜ける方法

Posted: 2013年7月28日(日) 18:52
by Lawliet
すいません。C言語です。このサイトも一応「C言語なんでも質問掲示板」でしたので
言語指定がない場合はデフォルトでC言語みたいなものだと勝手に思いこんでいました。

ソースで書くとこんなイメージです。

コード:

while( 1 ){
	if( ... ){
		break;	//脱出できるよ(^O^)/
	}
}

コード:

while( 1 ){
	switch( ... ){
		case /*終了したい値*/:
			break;	//脱出できない(TдT)
	}
} 

Re: switchでループを抜ける方法

Posted: 2013年7月28日(日) 18:59
by h2so5
僕はあまり使わないですけどgotoを使うとか...

コード:

    while( 1 ){
        switch( ... ){
            case /*終了したい値*/:
                goto endloop;
        }
    }
    endloop:

Re: switchでループを抜ける方法

Posted: 2013年7月28日(日) 19:01
by みけCAT
ただ、

コード:

endloop:
}
のようにラベルのあと即ブロックを終了するとエラーを吐かれるので、

コード:

endloop: ;
}
として回避します。

Re: switchでループを抜ける方法

Posted: 2013年7月28日(日) 19:54
by Lawliet
やっぱりC言語ではフラグを使ったりgotoを使ったりするしかないのでしょうか

何か他に裏技的な何かみたいなものはないものでしょうか?

Re: switchでループを抜ける方法

Posted: 2013年7月28日(日) 21:09
by みけCAT
関数にしてreturnとかでしょうか?

Re: switchでループを抜ける方法

Posted: 2013年7月28日(日) 22:00
by Lawliet
関数ですか、その発想はなかったです。

C言語にもさっきあげてくださったJAVAのような機能はないですよね・・・
と言うかそのJAVAもgotoと似たような機能ですが

Re: switchでループを抜ける方法

Posted: 2013年7月29日(月) 00:53
by softya(ソフト屋)
分かりやすくないと意味が無いので、gotoで抜けるかreturnで抜けた方が素直で追いかけやすいと思います。フラグは、ややこしくなったり関数が長くなりがちです。
裏技的なのは大体トリッキーなので避けないとひどい目に合いそうです。

Re: switchでループを抜ける方法

Posted: 2013年7月29日(月) 09:31
by Lawliet
確かに裏ワザにこだわって可読性が低下したら本末転倒ですもんね。

今まではフラグしか使って来なかったのでreturnというのは新鮮でした。

しかしどうにもgotoはつかってはいけないというイメージが僕の中では強いんですが
みなさんはどういう状況に陥った時にgotoを使いますか?
それとも、意地でもgotoは使いませんか?

Re: switchでループを抜ける方法

Posted: 2013年7月29日(月) 10:12
by usao
無限ループ+switch という状況が割とレアな気もしますが
そういったものを書くとしたら大抵関数化していると思うので普通にreturnです.
 ↓ どうしても関数化したくない場合
gotoは,一人で趣味で書いていてそのコードを読むのも触るのも自分だけ ということがわかっていて
且つ,今回のようなループ抜けのために限って ならば使うかもしれません.
そうでないならば たとえ見栄えが少々悪くなっても フラグを用意します.

コード:

//面倒だからifとswitchのハイブリッドで解決だ!…なんちゃって.
while(1)
{
    if( XXX )
    {//wihleを抜ける処理はこっち
        break;
    }
    else
    {//それ以外はこっち
        switch( ... )
        {
        }
    }
}

Re: switchでループを抜ける方法

Posted: 2013年7月29日(月) 13:25
by softya(ソフト屋)
flagがない方式の方が最終的には経験上バグにはなりづらいと思うので、私は分かりやすい抜け出しgotoなら仕事でも絶対拒否とは言いません。
ただ、私なら大抵はreturnに成る組み方にするか、処理テーブル方式にしているみたいで、error処理goto以外は無意識には避けている様です。なので、まずそういう状況にならないんですよね。つまり、switchでループ抜けするコードを書く状況が発生しないんです。

Re: switchでループを抜ける方法

Posted: 2013年7月29日(月) 13:38
by Lawliet
ただ、私なら大抵はreturnに成る組み方にするか、処理テーブル方式にしているみたいで、error処理goto以外は無意識には避けている様です。
あの、すいません。returnは分かるんですが処理テーブル方式ってどういうことでしょうか?

Re: switchでループを抜ける方法

Posted: 2013年7月29日(月) 13:57
by softya(ソフト屋)
処理テーブル方式は、わざわざフラグを立てなくてもテーブル自体がフラグやら状態のような役目を持つのでループを抜けるという状態をテーブルが持っていれば良いという話です。

Re: switchでループを抜ける方法

Posted: 2013年7月29日(月) 15:11
by Lawliet
softya(ソフト屋) さんが書きました:処理テーブル方式は、わざわざフラグを立てなくてもテーブル自体がフラグやら状態のような役目を持つのでループを抜けるという状態をテーブルが持っていれば良いという話です。
すみません。少し難しくてよくわからないです。
例えばコードでしたらどういった書き方が処理テーブル方式に当たるのでしょうか?

Re: switchでループを抜ける方法

Posted: 2013年7月29日(月) 15:22
by softya(ソフト屋)
switchで数値でcase分岐しますが、その数値をインデックスに使い構造体配列にアクセスして動作を決めるということです。

そうですね。こんな感じなら、そもそもswitchの出番がないと言った感じでしょう。

コード:

typedef struct {
	int bEnd;
	int ofsx;
	int ofsy;
} sw_t;

#define MAX_PATTERN 3
sw_t sw_array[MAX_PATTERN] = {
	{0,10,0}
	{0,-10,0}
	{1}
};

	while( 1 ) {
		if( sw_array[xx].bEnd ) {
			break;//ループ抜け
		}
		
		int bx= ax + sw_array[xx].ofsx;
		int by= ay + sw_array[xx].ofsy;
		
	}

Re: switchでループを抜ける方法

Posted: 2013年7月29日(月) 15:36
by softya(ソフト屋)
そうですね。
後思いついたのは、条件が多くない前提なら下記のように書くのも手ですよね。

コード:

	while( 1 ) {
		if( sw==1 ) {
			
		} else if( sw==2 ) {
			
		} else if( sw==3 ) {
			break; //ループを抜ける。
		}
	}

Re: switchでループを抜ける方法

Posted: 2013年7月29日(月) 15:50
by Lawliet
なるほど、こういうことだったのですね。

状況によってだとは思いますがこの処理テーブル方式ではコードが大きくなってくると見難くなりますよね。(パターンの数とか)
そうなってくるとやはりコードを書く頻度というのは
return方式 >  処理テーブル方式
となるのでしょうか?

それともコードが醜くなるといったことはないのでしょうか?

Re: switchでループを抜ける方法

Posted: 2013年7月29日(月) 16:15
by softya(ソフト屋)
>状況によってだとは思いますがこの処理テーブル方式ではコードが大きくなってくると見難くなりますよね。(パターンの数とか)

そうですか? 制御文で条件分けしなくて良いので大抵はコードがスッキリします。
テーブルの定義は表形式に近くなるので、Excelの表が見やすいのと同じです。

>そうなってくるとやはりコードを書く頻度というのは
>return方式 >  処理テーブル方式
>となるのでしょうか?

ケースバイケースなので何とも言えません。

Re: switchでループを抜ける方法

Posted: 2013年7月29日(月) 16:20
by usao
そのswitchによる分岐がどれだけのことをやっているのか,次第だと思います.

swtichでやってることが「ちょっとしたこと」であって,
少数のパターンしかなく,分岐後の処理も2~3行程度のコードで済む程度……とかであればif~elseで良いわけだし,
テーブルで済ませられるならそうすればいいし.

例えばswitchがやってることが
プログラムの状態に関わる大きな流れの制御だったりする場合,
Cなら関数ポインタ,C++ならStateパターンみたいなのを使うような場面かもしれませんし.

コード:

//関数ポインタで処理分岐
int (*pCurrStateFunc)() = InitStateFunc;

int InitStateFunc()
{
    ...
    //状態遷移
    if( XXX ){  pCurrStateFunc = StateFunc1;  }
    else if( YYY ){  pCurrStateFunc = StateFunc2;  }
    ...
    return 1;
}
int StateFunc1(){ ... }
int StateFunc2(){ ... }

//---while の部分
int main()
{
    while( 1 )  //メインループ
    {
        ...
        //アプリの現状態に合わせた処理を行う
        if( pCurrStateFunc() == 0 )break;  //※例えば戻り値でループを抜ける判断ができる決まりにしておく
    }
    ...

Re: switchでループを抜ける方法

Posted: 2013年7月29日(月) 16:33
by ISLe
ある程度大きいものなら、関数ポインタで関数呼び出したり、基底クラスのポインタから仮想関数呼び出したりしますから、そもそもswicth使いませんね。
メインループでswitch使って状態による分岐、なんてのは初心者向けのコードなわけで。

switchからループを抜ける状況というのは、十分小さいコードであるはずなのでgoto使っても問題ない気もします。


データテーブルはそもそも手で書かないことも多いですが、マクロ使って読みやすくすることも多いと思います。

コード:

#define MOVE(x, y) { 0, x, y }
#define END { 1 }
sw_t sw_array[MAX_PATTERN] = {
    MOVE(10,0),
    MOVE(-10,0),
    END
};

Re: switchでループを抜ける方法

Posted: 2013年7月29日(月) 17:46
by Lawliet
すいません。関数ポインタやクラスはまだ全然知らないのでぼくは何も言えません。

なのでこのへんでまとめにさせてもらいます。
*C言語で 無限ループ+switch を脱出する方法*
  1. フラグ
  2. goto文
  3. 関数化してreturn
  4. 処理テーブル方式
  5. 連続でif else
と教えて頂きました。
(僕の知識が足りない部分は不適切になると思い書きませんでした)

そもそも 無限ループ+switch文 というのがアレ とのご指摘も頂きました。

皆様、数多くの内容の濃い回答をありがとうございました。

Re: switchでループを抜ける方法

Posted: 2013年7月29日(月) 17:48
by softya(ソフト屋)
連続if else が抜けてますよ。 → No: 17

Re: switchでループを抜ける方法

Posted: 2013年7月29日(月) 17:53
by Lawliet
すいません。編集しときました。