c - romper - rompe la piñata video original
¿Cuál es una forma ordenada de romper muchos bucles a la vez? (14)
Supongamos que necesito separarme de tres o cuatro anidados para bucles a la vez al ocurrir algún evento dentro del bucle más interno. ¿Cuál es una forma limpia de hacer eso?
Lo que hago es usar banderas como esta:
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;
}
No creo que esto sea particularmente limpio.
¿Cómo lograrías lo mismo? (sin usar saltos)
¿Cómo lograrías lo mismo? (sin usar saltos)
¿Por qué? Nada es universalmente malo, y cada herramienta de aplicación tiene sus usos (excepto gets()
). Usar goto
aquí hace que su código se vea más limpio, y es una de las únicas opciones que tenemos (asumiendo que C). Mira:
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:
Mucho más limpio que todas esas variables de bandera, e incluso muestra más claramente lo que está haciendo su código.
A veces puedes usar truco como este:
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 declarar bandera de adición en su bucle:
bool end = false;
for(int i =0; i < 1000 && !end; i++) {
//do thing
end = true;
}
Sólo cuesta una línea pero limpia, creo.
justin
Dividir por 0 es el método más seguro que conozco que lo sacará de cualquier número de bucles. Esto funciona porque a la instrucción de montaje DIV no le gustan estas tonterías.
Entonces, puedes probar esto:
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;
}
Volviendo de la trap
que sucede en tales eventos, queda como un ejercicio para el lector (es trivial).
Haría algo como:
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;
}
}
}
}
Ponga todos los bucles en una función y simplemente regrese en lugar de romper.
Sólo un poquito mejor.
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;
}
}
}
}
Pero si realmente necesita tener esos bucles, entonces tiene sentido declarar explícitamente en cada bucle las condiciones que deben cumplirse para que continúe, para facilitar la lectura.
Si está utilizando GCC y esta biblioteca , la break
puede aceptar el número de bucles anidados que desea salir:
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);
}
}
}
}
Si está utilizando Java, puede asociar etiquetas con cada bloque y luego hacer referencia a la etiqueta después de una declaración de continuación. Por ejemplo:
outerfor:
for (int i=0; i<5; i++) {
innerfor:
for (int j=0; j<5; j++) {
if (i == 1 && j == 2) {
continue outerfor;
}
}
}
Si la finalización prematura de cualquier ciclo siempre significa que también tiene que romper el ciclo de cierre, no necesita ningún indicador adicional. Todo el asunto podría verse como sigue
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;
}
En mi experiencia, esto es lo que se necesita en la mayoría de los casos.
Si no quieres usar goto, configura todas las condiciones del bucle como falsas:
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 compilador de optimización inteligente cambiará el contenido de si en un salto al final del bucle más exterior
Una forma de hacerlo es una máquina de estados. Pero todavía usaría goto. Es mucho más simple. :)
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;
}
}
un poco de auto-documentación tonta:
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;
}
Pero en realidad, no deberías tener tres bucles forados anidados. Debería considerar refactorizar en diferentes funciones y mejorar la lógica de su programa en lugar de hacerlo.
Si bien estoy de acuerdo en que a veces goto
es realmente la mejor solución, creo que cualquier problema para el que goto
es la solución es el resultado de un código deficiente.
utilizar goto. Es limpio y simple.
goto
Este es uno de los pocos lugares donde goto
es la herramienta adecuada, y generalmente es el argumento que se presenta por qué goto
no es un completo mal.
A veces, sin embargo, hago esto:
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;
}
}
}
}
La idea es que obtengo una barra libre garantizada, y además obtengo una interrupción limpia del conmutador de dos niveles a través del retorno.