ネストされたループから抜け出す方法は?


96

breakステートメントを使用すると、内側のループのみが解除され、外側のループを解除するためにいくつかのフラグを使用する必要があります。ただし、ネストされたループが多数ある場合、コードは適切に表示されません。

すべてのループを解除する他の方法はありますか?(使用しないでくださいgoto stmt。)

for(int i = 0; i < 1000; i++) {
   for(int j = 0; j < 1000; j++) {
       if(condition) {
            // both of the loops need to break and control will go to stmt2
       }
   }

}

stmt2

2
ループが始まる前にint iとint jを試してみて、その条件で1001にすると、ループは次のループを繰り返しません。
Khurram Ijaz 2012年

回答:


43

使用する:

if (condition) {
    i = j = 1000;
    break;
}

49
動作しますが、醜く、一般的ではありません。誰かが制限を2000に変更するとどうなりますか(コードが長いため、すぐに気付かない場合)。
ugoren 2012

1
@ugorenそのときもとても簡単です。const int count =1000 グローバル初期化でを使用した場合はどうなりますか?または#defineマクロとして。
Laksith

4
@ugorenが指摘するように、これは一般的な解決策ではありません。これはこの質問に対する最初のGoogleヒットであるため、一般的なソリューションが選択されていればすばらしいと思います。とにかく、人々は#2をチェックアウトすることに慣れています。
BeeOnRope 2016年

1
私はi = 1000だけが必要だと思いますか?
Peter Wu

189

いいえ、で楽しいを台無しにしないでくださいbreak。これがgoto;)の最後の有効な使用法です。

そうでない場合は、フラグを使用して深くネストされたループから抜け出すことができます。

ネストされたループから抜け出す別のアプローチは、両方のループを別々の関数に分解し、終了したいときにその関数から戻ることです。

要約-ネストされたループから抜け出すには:

  1. 使用する goto
  2. フラグを使用する
  3. ループを個別の関数呼び出しに分解する

ここにxkcdを含めることに抵抗できませんでした:)

ここに画像の説明を入力してください

ソース

後藤は有害と考えられていますが、コメントの多くの人がそうである必要はないと示唆しています。慎重に使用すれば、優れたツールになる可能性があります。節度で使用されるものはすべて楽しいです。


29
後藤はあなたがここに来るのと同じくらいはっきりしています、ええ。exit変数を1000に設定することは、さらに厄介です。
correnos 2012年

3
後藤は明らかに悪ではなく、悪のためにのみ使用できることを付け加えておきます。これが最適なソリューションである場合など、かなりの数のケースがあることがわかりました。「ゴトスを使わない」は良いスタートですが、スキルの次のステップでは「長距離ゴトスを使わない」ことができると思います。
Aatch

1
私はこれに反対したいと思います:「関数を作成すると、スタックポインターの指数関数的な量の加算/減算が発生します」。プログラムフローの1点のみで呼び出されるローカル(静的)関数がある場合、適切なコンパイラーはそれをインライン化し、結果のコードは基本的にgotoと同じです。これは、おそらくコンパイラにとって最も簡単な最適化ケースです。
DrV 2017年

1
通常、リファクタリングは最もクリーンなソリューションです。ただし、ループの外側の変数が内側のループの間に変更されると、事態は複雑になります。1つの可能性は、変数を参照(ポインター)によって内部関数に渡すことですが、これはコンパイラーの最適化を混乱させ、不要な余分なコードを生成する可能性があります。別の可能性は、そのような変数をモジュールレベルで静的にすることですが、それもあまり美しくありません。Cは、この問題を解決するため、残念ながらネストされた関数がありません—拡張機能を提供するgccの使用に自分をバインドするつもりがない限り。
DrV 2017年

1
+1。また、go to Statements(wiki.c2.com/?StructuredProgrammingWithGoToStatements)を使用したドナルドE.クヌースの構造化プログラミングは、ダイクストラのバランスをとるための興味深い記事です。
kmkaplan 2018年

40
bool stop = false;
for (int i = 0; (i < 1000) && !stop; i++)
{
    for (int j = 0; (j < 1000) && !stop; j++)
    {
        if (condition)
            stop = true;
    }
}

解決策では、問題が発生する可能性があるブレーク時に両方の変数が1つずつインクリメントされる
TheSola10

7
「stop = true;」を設定できます。そして「壊れる」。次に、内側の「for」ループの終わりの直後に、「if(stop)break;」を実行します。
ジェフグリッグ2017

34

1つの方法は、すべてのネストされたループを関数に入れ、すべてのループから抜ける必要がある場合に最も内側のループから戻ることです。

function() 
{    
  for(int i=0; i<1000; i++)
  {
   for(int j=0; j<1000;j++)
   {
      if (condition)
        return;
   }
  }    
}

1
私にとって最良の解決策のようです
Luca Steeb

20

gotoは問題を解決すると思います

for(int i = 0; i < 1000; i++) {
    for(int j = 0; j < 1000; i++) {
        if (condition) {
            goto end;
        }
    }
}

end:
stmt2 

@chikuba私から答えを得たcprogramming.com/tutorial/goto.htmlと私はあなたのポストを参照してくださいいけない、なぜ私は同じことのthatsのをやっているとき、あなたの答えが掲載されていません
Renjith KN

15

読みやすくしたい場合は、ブール変数が必要です。

bool broke = false;
for(int i = 0; i < 1000; i++) {
  for(int j = 0; j < 1000; i++) {
    if (condition) {
      broke = true;
      break;
    }
  }
  if (broke)
    break;
}

読みにくくしたい場合は、ブール評価に参加できます。

bool broke = false;
for(int i = 0; i < 1000 && !broke; i++) {
  for(int j = 0; j < 1000; i++) {
    if (condition) {
      broke = true;
      break;
    }
  }
}

最終的な方法として、初期ループを無効にすることができます。

for(int i = 0; i < size; i++) {
  for(int j = 0; j < 1000; i++) {
    if (condition) {
      i = size;
      break;
    }
  }
}


4

注意:この回答は、本当にあいまいな構造を示しています。

GCCを使用している場合は、このライブラリを確認してください。PHPと同様に、break終了する入れ子ループの数を受け入れることができます。次のように書くことができます:

for(int i = 0; i < 1000; i++) {
   for(int j = 0; j < 1000; j++) {
       if(condition) {
            // break two nested enclosing loops
            break(2);
       }
   }
}

そして、実際にはそれは実際に:) を使用していgotoます
iX3

@ iX3役立つ場合は、インラインアセンブラーとjmp命令を使用できます。
DaBler

@DaBler、あなたがそのライブラリの作者であることに気づかなかった。私のコメントはフィードバックではなく、このライブラリが受け入れられた回答と同じ方法を使用していることを示していました。おそらく、あなたのコメントは冗談として意図されたものです。私は、言語機能(もgoto)を使用する方が、asmをインライン化するほうがはるかに好ましい(マシン固有、間違いが起こりやすく、読みにくいなど)と考えています。
iX3

3
for(int i = 0; i < 1000; i++) {
   for(int j = 0; j < 1000; i++) {
       if(condition) {
            goto end;
   }
} 

end:

3

iとjの値が必要な場合、これは機能するはずですが、他よりもパフォーマンスは低くなります。

for(i;i< 1000; i++){    
    for(j; j< 1000; j++){
        if(condition)
            break;
    }
    if(condition) //the same condition
        break;
}

条件が依存している場合、これが機能するためには、条件jの値を何らかの方法で格納する必要があることに注意してください。
SuperBiasedMan

1
あなたは正しいですが、breakの後、jの値は変化せず、条件の値も変化しません。
Ali ErenÇelik

これは壊れたソリューションであり、一般的には無効です。jがループの外側で定義されていないか、内側のループの最初の反復後for (int i = 0; i < 1000; i++) { for (int j = 0; j < 1000; j++) { if (workComplete[i][j]) break; /* do work */ workComplete[i][j] = true; } if (workComplete[i][j]) break; ... }常に外側のループから抜け出します。
Chai T. Rex

-3
int i = 0, j= 0;

for(i;i< 1000; i++){    
    for(j; j< 1000; j++){
        if(condition){
            i = j = 1001;
            break;
        }
    }
}

両方のループが壊れます。


-3
for(int i = 0; i < 1000; i++) {
    for(int j = 0; j < 1000; i++) {
       if(condition) {
          func(para1, para2...);
          return;
       }
    }
}

func(para1, para2...) {
    stmt2;
}

つまり、基本的には、(1)追加の関数呼び出しの束を作成し、(2)conditionfalse になると残りの時間スピンする必要があると言います。ああ、それはインクリメントため、2番目のループは永久に実行されるi代わりにj...、おっとを
IX3

-4
i = 0;

do
{
  for (int j = 0; j < 1000; j++) // by the way, your code uses i++ here!
  {
     if (condition)
     {
       break;
     }
  }

  ++i;

} while ((i < 1000) && !condition);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.