Ist es möglich, ein für zu beenden, bevor die Zeit in C ++, wenn eine Endbedingung erreicht ist?

StackOverflow https://stackoverflow.com/questions/416464

  •  03-07-2019
  •  | 
  •  

Frage

Ich mag wissen, ob es möglich ist, ein for-Schleife in C ++ zu beenden, wenn eine Endbedingung (abweichend von der reacheing richtigen Anzahl von Iterationen) überprüft wird. Zum Beispiel:

for (int i = 0; i < maxi; ++i)
    for (int j = 0; j < maxj; ++j)
        // But if i == 4 < maxi AND j == 3 < maxj, 
        // then jump out of the two nested loops.

Ich weiß, dass dies in Perl mit den nächsten Etikett oder letzten LABEL Anrufen und markierten Blöcken möglich ist, ist es möglich, sie in C ++ zu tun oder ich soll eine while-Schleife verwenden?

Danke.

War es hilfreich?

Lösung

Sie können das return Schlüsselwort verwenden: die verschachtelte Schleife in ein Unterprogramm bewegen, rufen Sie das Unterprogramm die verschachtelten Schleifen laufen, und ‚Rückkehr‘ aus dem Unterprogramm zu beenden [alles] die Schleifen

.

Andere Tipps

Trotz der „goto als schädlich“ Argumente, scheint dies der ideale Ort für goto. Das ist im Wesentlichen, was Sie in Perl tun. Ernsthaft ... betrachten die Alternativen:

Zusätzliche Zustandsvariablen


for (int i=0; i<maxi; ++i) {
    bool leaveLoop = false;
    for (int j=0; j<maxj; ++j) {
        if (i == 4 && j == 3) {
            leaveLoop = true;
            break; // leave the inner loop
        }
    }
    if (leaveLoop) {
        break; // leave the outside loop
    }
}

Lassen by Exception


try {
    for (int i=0; i<maxi; ++i) {
        for (int j=0; j<maxj; ++j) {
            if (i == 4 && j == 3) {
                throw leave_loop();
            }
        }
    }
} catch (leave_loop const&) {
}

komplexe Logik


int j = 0;
for (int i=0; i<maxi && !(i==4 && j==3); ++i) {
    for (j=0; j<maxj && !(i==4 && j==3); ++j) {
        // inner loop
    }
}

goto


for (int i=0; i<maxi; ++i) {
    for (int j=0; j<maxj; ++j) {
        if (i==4 && j==3) {
            goto leave_loop;
        }
    }
}
leave_loop:

Ist der letzte weniger klar? Ich glaube nicht, dass es ist. Ist es ein zerbrechlicher? IMHO, die andere sind ziemlich fehleranfällig und zerbrechlich im Vergleich zur goto Version. Es tut uns Leid hier auf der Seifenkisten zu stehen, aber das ist etwas, das mich für eine Weile gestört hat;)

Das einzige, was Sie werden müssen congnizent ist, dass goto und Ausnahmen sind ziemlich ähnlich. Beide eröffnen die Möglichkeit, Ressourcen undicht ist und was nicht so behandeln sie mit Vorsicht.

Lassen Sie mich sagen, wie emphatisch (aber höflich ;-), wie ich kann. Die for in c-ähnliche Sprache konstruieren ist nicht über das Zählen

Der Ausdruck Test der bestimmt, ob können weiterhin alles sein, die dem Zweck der Schleife relevant ist; der Update Ausdruck muss nicht sein „ein zu einem Zähler hinzufügen“.

for (int i = 0, j = 0; i < maxi && j < maxj && i != 4 && j != 3;) {
    if (j < maxj) {
        ++j;
    } else {
        j = 0;
        ++i;
    }
}

würde man (ziemlich willkürlich) Art und Weise sein, neu zu schreiben.

Der Punkt ist, dass, wenn eine Bedingung zur Gründung der Punkt eines interation ist, ist es in der Regel möglich ist, eine Schleife zu schreiben, in einer Art und Weise (entweder while oder for verwenden), die die weiterhin die Staaten / Abbruchbedingung mehr explizit.

(Wenn Sie eine Beschreibung von posten könnten, was tatsächlich geschieht, würde es wahrscheinlich, etwas zu schreiben, die nicht so willkürlich wie die oben sehen.)

Sie können nicht aus springen zwei Schleifen mit einer einzigen Pause Anweisung, aber man konnte direkt vor eine goto springen von der inneren Schleife verwenden.

Wenn der goto lokalisiert ist, und bedeutet, dass es weniger Logik als sonst halte ich es für durchaus akzeptabel Code ist. aus der inneren Schleife zusätzliche Flag-Variablen zu haben, oder die Iteratorvariable Hebe, so dass Sie es in der äußeren Schleife vergleichen kann nicht für erleichtern Code IMHO zu verstehen.

Von all den oben genannten Vorschläge mir vermeiden würde mit der Try / Catch Mechanismus, weil Ausnahmen für außergewöhnliche Umstände reserviert werden sollen, und nicht normaler Kontrollfluss.

Mit zwei Pausen ist in Ordnung, wenn Sie die zweite Bedingung entsprechend erstellen können. einen boolean für diesen Zweck wäre auch gut, und man konnte es sogar in den Zustand jeder für Schleife verdrahten. Zum Beispiel:

bool exit_loops = false;
for (int a = 0; a < A && !exit_loops; ++a)
{
    for (int b = 0; b < B && !exit_loops; ++b)
    {
        if (some_condition) exit_loops = true;
    }
}

Obwohl, wenn Sie mehr als zwei Schleifen verwenden, es könnte besser geeignet sein, um sie in einer Funktion zu wickeln und nur Rückkehr verwenden, um die Funktion zu verlassen (und alle Schleifen auch). Dann wieder können Sie den Code in einer Weise umgestalten, die alle bis auf eine der Schleifen zu beseitigen, sei es durch den Aufruf einer Funktion der inneren Schleife Code auszuführen, etc.

Schließlich fürchtet mich nicht eine goto unter diesen Umständen zu verwenden, in der Regel GOTOs ist schlecht unstrukturierten Programmierung, aber in einigen Fällen (wie diese) sind sie sehr nützlich.

bool done = false;

for (int i = 0; i < maxi && !done; ++i)
    for (int j = 0; j < maxj && !done; ++j)
        if (i == 4 && i < maxi && j == 3 && j < maxj )
             done = true;
        else {
        }

Oder Sie könnten nur gehe. Oder auch nicht: -)

Sie können wie diese nicht herausspringen in C / C ++:

for (...)
{
  for (...)
  {
    // from here...
  }
}
// ...to here

ohne die Verwendung von goto. Sie benötigen ein Konstrukt wie:

for (...)
{
  bool
    exit = false;

  for (...)
  {
    if (do_exit)
    {
      exit = true; // or set outer loop counter to end value
      break;
    }
  }
  if (exit)
  {
    break;
  }
}

Alternativ können Sie werfen und zu fangen -. Aber das ist nicht groß, da throw wirklich für Ausnahmen verwendet werden soll und nicht die Kontrolle fließt

Eine saubere Art und Weise ist die innere Schleife eine Funktion zu machen:

bool F ()
{
  if inner loop terminates, return false else return true
}

void G ()
{
  for (...)
  {
    if (!F ())
    {
      break;
    }
  }
}
for (int i = 0; i < maxi; ++i)
{
    int j = 0;
    for (j = 0; j < maxj; ++j)
    {
         if (i == 4 && j == 3) // i < maxi and j < maxj otherwise we would not be here
             break; // exit inner loop
    }
    if (i == 4 && j == 3) // i < maxi and j < maxj otherwise we would not be here
        break; // exit outer loop
}

könnten Sie verwenden einen goto , aber das eine schlechte Praxis allgemein betrachtet wird.

Die andere Option ist, so etwas zu tun

int i;
int j = 0;
for (i = 0; i < maxi && !(i==4 && j==3); ++i)
    for (j = 0; j < maxj && !(i==4 && j==3); ++j)

Code Lesen sollte nicht wie ein Detektiv Buch zu lesen (die immer müssen herausgefunden werden) ...

ein Beispiel:

Java:

iterate_rows:
for (int i = 0; i < maxi; ++i)
{       
    for (int j = 0; j < maxj; ++j)
    {
        if (i == 4 < maxi && j == 3 < maxj) 
            break iterate_rows;
        else
            continue iterate_rows;
    }   
}

Sie müssen nicht herausfinden, was zu brechen iterate_rows tun, können Sie es nur lesen.

C ++:

//iterate_rows:
for (int i = 0; i < maxi; ++i)
{
    for (int j = 0; j < maxj; ++j)
    {
        if (i == 4 < maxi && j == 3 < maxj) 
            goto break_iterate_rows;
        else
            goto continue_iterate_rows;
    }

continue_iterate_rows:;
}
break_iterate_rows:;

goto break_iterate_rows ist nur eine sichtbar Version von brechen iterate_rows

Wenn Sie Ihre Verwendung von goto und Etiketten auf diese Art von Code nur darauf beschränken, werden Sie nicht die Absicht herauszufinden werden. Die Begrenzung der Nutzung von goto und Etiketten auf diese Art von Code werden Sie den Code nur lesen, nicht zu analysieren oder herauszufinden es aus. Sie werden nicht zu sein, ein böser Programmierer beschuldigt werden.

Und wenn Sie wirklich Ihre gotos in dieser Art von Code begrenzen, werden Sie in der Lage sein, eine Gewohnheit, nicht diese verflixten gotos tun in Ihrem Code, um herauszufinden, um zu entwickeln, was. Vorteil ist, Sie müssen nicht booleans einführen und verfolgen sie (was imho, führt Sie zu den Code Erkennung , es ein bisschen unleserlich zu machen, die den Zweck besiegt gotos zu vermeiden)

P. S.

Paare dieser Etiketten mit Kommentaren (vor der Schleife), durch die Zeit, die Sie diese Zeilen lesen Vergangenheit mit goto-Anweisung kennen Sie bereits die Absicht dieses gotos

Ich habe ein paar Vorschläge:

  1. werfen .... setzen die zwei Schleifen in einem "try {}" und "fangen" die "werfen" dann auf den Zustand.

  2. Die beiden Schleifen in einem Verfahren setzen und zurück auf den Zustand.

  3. Goto ist nicht böse sein die Verwendung Menschen es zu setzen .... Sie können mit „goto“ kann es der deutlichste Code sein, vor allem, wenn die Fehlerbehandlung. Ich habe nicht ein in 20 Jahren.

  4. verwendet

Tony

Ich habe immer versucht, aus goto Aussagen zu bleiben weg (es war immer auf aus irgendeinem Grunde in der Schule und meine Arbeit sieht nach unten). Ich würde so etwas wie verwenden, was Daemin vorgeschlagen.

Sie können Etiketten verwenden, etwas entlang der Linien von:

Outer:
for(...)
{
    Inner:
    for(...)
    {
    if(condition)
        {
        goto End;
        }
    }
}
End:

In Java können Sie Etiketten passieren zu brechen Ich denke?

Bearbeiten - Changed die goto zu beenden, anstatt Outer, aber ich glaube nicht, dass die negativen rep gerechtfertigt ist. Diese Antwort gibt den einfachste Weg, es zu tun.

Ein weiterer Grund für das Überdenken for Konstrukts vollständig ist, dass sein Scoping Zugriff auf die Regelgrößen verhindert, nachdem die Schleife beendet wird. Der Wert (e) der Variablen (n) in der Schleife mutiert kann für eine Vielzahl von Gründen nützlich (z Erfolg von Versagen bei der Suche zu unterscheiden), die ansonsten zusätzliche Variablen erfordern würde, dass die Informationen nach Umfang Ausgang zu erhalten. Hier ist ein kleines Beispiel, das eine quadratische Anordnung namens a für einen target Wert sucht (unter der Annahme, dass SIZE ist nicht Null, da sonst keine Suche erforderlich!):

int i = 0;
int j = 0;
while (i < SIZE && a[i][j] != target) { // still in array but not at target
    if (SIZE <= ++j) {                  // fallen off the end of a row
        j = 0;
        ++i;
    }
}

Der nachfolgende Code i < SIZE verwenden kann, um zu bestimmen, ob der gewünschte Wert gelegt wurde.

Ein weiterer Vorteil der oben ist die Flexibilität. Angenommen, wir sind jetzt darüber informiert, dass die Werte in den Reihen von a sind aufsteigend, so dass der Rest einer Reihe irrelevant ist, ob ein Wert größer als target angetroffen wird. Es ist einfach, genau zu wissen, was zu machen ändern, und wo es zu machen. Da die neuen Informationen ermöglichen es uns, die aktuelle Zeile zu verlassen, nur die innere Entscheidung betroffen ist, werden:

    if (target < a[i][j] || SIZE <= ++j) { // can't be in row or fallen off end
    ...

Ich bin mehr die neueren Sprachen zu sehen (besonders funktionsorientiert sind), das alte „Zählen“ Schleifenkonstrukt zu verlassen; das ist wahrscheinlich eine gute Sache, da es uns über die Sinn der Schleife zu denken ermutigt, anstatt einfach nur zu zählen.

Der beste Weg, die ich gesehen habe Makros und gotos beinhaltet, aber es ist eigentlich ganz schön (die beginnt zu schreiben, indem er über Perl verbunden, aber der letzte Absatz oder stellt so die Makros).

Es ermöglicht Ihnen, Code zu schreiben wie:

named (LOOPS) for (i=1; i<10; i++) {
    for (j=1; j<10; j++) {
        for (j=1; j<10; j++) {
            /* Process data[i][j][k] here */
            if (data[i][j][k] < threshold) break(LOOPS);
        }
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top