Che è un modo pulito di rottura di molti cicli for in una sola volta?
Domanda
E se ho bisogno di uscire di tre o quattro cicli for innestati in una sola volta al verificarsi di un evento all'interno del ciclo più interno. Che cosa è un modo pulito di fare questo?
quello che faccio è utilizzare bandiere in questo modo:
int i, j, k;
int flag1 = 0;
int flag2 = 0;
for (i = 0; i < 100; i++) {
for (j = 0; j < 100; j++) {
for (k = 0; k < 100; k++) {
if (k == 50) {
flag1 = 1;
flag2 = 1;
break;
}
}
if (flag1 == 1)break;
}
if (flag2 == 1)break;
}
Non credo che questo è particolarmente accurata.
Come vi ottenere la stessa cosa? (w / o utilizzando salti)
Soluzione
uso goto. è pulito e semplice.
Altri suggerimenti
Mettere tutti i loop in una funzione e proprio ritorno al posto di rottura.
Se stai usando Java, è possibile associare le etichette con ogni per il blocco e quindi fare riferimento sull'etichetta dopo una dichiarazione continuare. Ad esempio:
outerfor:
for (int i=0; i<5; i++) {
innerfor:
for (int j=0; j<5; j++) {
if (i == 1 && j == 2) {
continue outerfor;
}
}
}
Come vi ottenere la stessa cosa? (w / o utilizzando salti)
Perché? Nulla è universalmente male, e ogni mettere-upon strumento ha la sua utilità (ad eccezione gets()
). Utilizzando goto
qui rende il più pulito il codice aspetto, ed è una delle poche scelte che abbiamo (assumendo C). Guardate:
int i, j, k;
for (i = 0; i < 100; i++) {
for (j = 0; j < 100; j++) {
for (k = 0; k < 100; k++) {
if (k == 50) {
goto END;
}
}
}
}
END:
Molto più pulito rispetto a tutte quelle variabili di bandiera, e si vede anche più chiaramente ciò che il codice è fare .
solo un pochino meglio.
int i, j, k;
int flag1 = 0;
int flag2 = 0;
for (i = 0; i < 100 && !flag2; i++) {
for (j = 0; j < 100 && !flag1; j++) {
for (k = 0; k < 100; k++) {
if (k == 50) {
flag1 = 1;
flag2 = 1;
break;
}
}
}
}
Ma se davvero bisogno di avere questi cicli, allora ha senso esplicitamente dichiarando in ogni ciclo quali condizioni devono essere in possesso per poter continuare, per migliorare la leggibilità.
goto
. Questo è uno dei pochi posti in cui goto
è lo strumento appropriato, e di solito è l'argomento presentato perché goto
non è completa il male.
A volte, però, faccio questo:
void foo() {
bar_t *b = make_bar();
foo_helper(bar);
free_bar(b);
}
void foo_helper(bar_t *b) {
int i,j;
for (i=0; i < imax; i++) {
for (j=0; j < jmax; j++) {
if (uhoh(i, j) {
return;
}
}
}
}
L'idea è che ho un garantito privo di bar, oltre a ricevo una pausa di due livelli pulire l'esterno dello switch via di ritorno.
Se proprio non si vuole utilizzare goto, impostare tutte le condizioni di loop su false:
int i, j, k;
for (i = 0; i < 100; i++) {
for (j = 0; j < 100; j++) {
for (k = 0; k < 100; k++) {
if (k == 50) {
i = j = k = INT_MAX;
break;
}
}
}
}
Nota: un compilatore ottimizzato intelligente girerà il contenuto del caso in un salto alla fine del ciclo più esterno
a volte è possibile utilizzare trucco in questo modo:
for (i = 0; i < 100 && !flag2; i++) {
for (j = 0; j < 100 && !flag1; j++) {
for (k = 0; k < 100; k++) {
if (k == 50) {
k = 100;
i = 100;
j = 100;
}
}
}
}
o dichiarare la bandiera aggiunta nel ciclo:
bool end = false;
for(int i =0; i < 1000 && !end; i++) {
//do thing
end = true;
}
costa solo una linea, ma pulita, credo.
justin
Se il completamento prematura di ogni ciclo significa sempre che si deve interrompere il ciclo racchiude pure, quindi non è necessario alcun flag extra. Il tutto potrebbe basta guardare come segue
int i, j, k;
for (i = 0; i < 100; i++) {
for (j = 0; j < 100; j++) {
for (k = 0; k < 100; k++) {
if (k == 50)
break;
}
if (k < 100) break;
}
if (j < 100) break;
}
Nella mia esperienza, questo è ciò che è necessario in maggior parte dei casi.
un po 'di sciocco auto-documentazione:
int i, j, k;
int done = 0;
for (i = 0; i < 100 && ! done; i++) {
for (j = 0; j < 100 && ! done; j++) {
for (k = 0; k < 100 && ! done; k++) {
if (k == 50) we_are(done);
}
}
}
//...
void we_are(int *done) {
*done = 1;
}
, ma in realtà, non dovreste avere tre nidificati per-loop. Si dovrebbe prendere in considerazione il refactoring in funzioni diverse e migliorare la logica del vostro programma invece di fare questo.
Mentre sono d'accordo che a volte goto
è davvero la soluzione migliore, credo che qualsiasi problema a cui goto
è la soluzione è il risultato di codice di poveri.
La divisione per 0 è il metodo più sicuro so che si romperà fuori di qualsiasi numero di cicli. Questo funziona perché le istruzioni di montaggio DIV non piace come sciocchezze.
Quindi, si può provare questo:
int i, j, k;
int flag1 = 0;
int flag2 = 0;
for (i = 0; i < 100; i++) {
for (j = 0; j < 100; j++) {
for (k = 0; k < 100; k++) {
if (k == 50) {
flag1 = 1;
flag2 = 1;
int z = 1 / 0; // we're outta here!!!
}
}
if (flag1 == 1)break;
}
if (flag2 == 1)break;
}
Tornando dal trap
che accade su tali eventi hanno lasciato come esercizio per il lettore (è banale).
mi piacerebbe fare qualcosa di simile:
int i, j, k;
for (i = 0; i < 100; i++) {
for (j = 0; j < 100; j++) {
for (k = 0; k < 100; k++) {
if (k == 50) {
return;
}
}
}
}
Se si sta utilizzando GCC e questa libreria , il break
può accettare il numero di nidificato loop si vuole uscire:
int i, j, k;
for (i = 0; i < 100; i++) {
for (j = 0; j < 100; j++) {
for (k = 0; k < 100; k++) {
if (k == 50) {
break(3);
}
}
}
}
Un modo per farlo è una macchina a stati. Ma vorrei ancora usare goto. E 'molto più semplice. :)
state = 0;
while( state >= 0){
switch(state){
case 0: i = 0; state = 1; // for i = 0
case 1:
i++;
if (i < 100) // if for i < 100 not finished
state = 2; // do the inner j loop
else
state = -1; // finish loop
case 2: j = 0; state = 3; // for j = 0
case 3:
j++;
if (j < 100) // if j < 100 not finished
state = 4 // do the inner k loop
else
state = 1; // go backt to loop i
break;
case 4: k = 0; state = 5;
case 5:
k++;
if (k == 50){
state = -1;
break;
}
if (k < 100) // if k loop not finished
state = 5; // do this loop
else
state = 3; // go back to upper loop
break;
default : state = -1;
}
}