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)

È stato utile?

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;
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top