¿Cómo salir de los bucles anidados?

96

Si utilizo una breakdeclaración, solo romperá el bucle interno y necesito usar alguna bandera para romper el bucle externo. Pero si hay muchos bucles anidados, el código no se verá bien.

¿Hay alguna otra forma de romper todos los bucles? (No lo use 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
usuario966379
fuente
2
puede probar int i e int j antes de que comience el ciclo y luego, con la condición de que sean 1001, el ciclo no repetirá el siguiente.
Khurram Ijaz
Versión C ++: stackoverflow.com/questions/1257744/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:

43

Utilizar:

if (condition) {
    i = j = 1000;
    break;
}
Peter Mortensen
fuente
49
Funciona, pero feo y no general. ¿Qué pasa si alguien cambia el límite a 2000 (suponga que el código es más largo, por lo que no lo nota de inmediato)?
ugoren
1
@ugoren También es tan simple entonces. ¿Qué pasa si utiliza un const int count =1000 , en la inicialización global. o como una #definemacro.
Laksith
4
Como señala @ugoren, no es una solución general. Dado que este es el primer resultado de Google para esta pregunta, sería bueno si se hubiera seleccionado la solución general. Bueno, la gente está acostumbrada a ver el número 2 de todos modos.
BeeOnRope
1
¿Supongo que solo necesito i = 1000?
Peter Wu
189

No, no estropees la diversión con un break. Este es el último uso válido restante de goto;)

Si no es así, puede usar banderas para salir de bucles anidados profundos.

Otro enfoque para salir de un bucle anidado es factorizar ambos bucles en una función separada y volver de esa función cuando desee salir.

Resumido: para salir de bucles anidados:

  1. utilizar goto
  2. usar banderas
  3. factorizar los bucles en llamadas de función separadas

No pude resistirme a incluir xkcd aquí :)

ingrese la descripción de la imagen aquí

fuente

Los Goto se consideran dañinos, pero como sugieren muchas personas en los comentarios, no es necesario. Si se usa con prudencia, puede ser una gran herramienta. Cualquier cosa que se use con moderación es divertida.

Srikar Appalaraju
fuente
29
Ir a es lo más claro que obtendrás aquí, sí. Establecer la variable de salida en 1000 es aún más complicado.
correnos
3
Me gustaría agregar que los gotos no son explícitamente malvados, solo pueden usarse para el mal. Encuentro que hay bastantes casos, por ejemplo este, en los que son la mejor solución. "No uses gotos" es un buen comienzo, pero creo que el siguiente paso en la habilidad te permite "No uses gotos de largo alcance".
Aatch
1
Me gustaría no estar de acuerdo con esto: "La creación de una función da como resultado cantidades exponenciales de suma / resta del puntero de la pila". Si hay una función local (estática) a la que se llama en un solo punto del flujo del programa, cualquier compilador medio decente la incorporará y el código resultante es esencialmente el mismo que con goto. Este es posiblemente el caso de optimización más fácil para cualquier compilador.
DrV
1
La refactorización suele ser la solución más limpia. Sin embargo, si se cambia alguna variable fuera del ciclo durante el ciclo interno, las cosas se complican. Una posibilidad es pasar la variable a la función interna por referencia (puntero), pero esto puede confundir la optimización del compilador y producir código adicional innecesario. Otra posibilidad es hacer que estas variables sean estáticas a nivel de módulo, pero eso tampoco es muy bonito. Desafortunadamente, a C le faltan funciones anidadas, ya que resolverían este problema, a menos que esté dispuesto a vincularse al uso de gcc, que proporciona una extensión.
DrV
1
+1. Y Programación estructurada de Donald E. Knuth con go to Statements ( wiki.c2.com/?StructuredProgrammingWithGoToStatements ) es un artículo interesante para equilibrar el de Dijkstra.
kmkaplan
40
bool stop = false;
for (int i = 0; (i < 1000) && !stop; i++)
{
    for (int j = 0; (j < 1000) && !stop; j++)
    {
        if (condition)
            stop = true;
    }
}
Tung
fuente
La solución aún incrementa ambas variables en una en la ruptura, lo que puede causar problemas
TheSola10
7
Se puede establecer "stop = true"; y luego "romper". Luego, justo después del final del bucle "for" interior, haz "if (stop) break;".
Jeff Grigg
34

Una forma es poner todos los bucles anidados en una función y regresar desde el bucle más interno en caso de que sea necesario salir de todos los bucles.

function() 
{    
  for(int i=0; i<1000; i++)
  {
   for(int j=0; j<1000;j++)
   {
      if (condition)
        return;
   }
  }    
}
Arrendajo
fuente
1
parece la mejor solución para mí
Luca Steeb
20

Creo gotoque solucionará el problema

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

end:
stmt2 
Renjith KN
fuente
@chikuba Obtuve respuesta de cprogramming.com/tutorial/goto.html y su respuesta no se publica cuando estoy haciendo lo mismo, por eso no veo su publicación
Renjith KN
15

Necesitará una variable booleana, si quiere que sea legible:

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;
}

Si lo desea menos legible, puede unirse a la evaluación booleana:

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

Como forma definitiva, puede invalidar el bucle inicial:

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

Precaución: esta respuesta muestra una construcción verdaderamente oscura.

Si está utilizando GCC, consulte esta biblioteca . Como en PHP, breakpuede aceptar el número de bucles anidados que desea salir. Puedes escribir algo como esto:

for(int i = 0; i < 1000; i++) {
   for(int j = 0; j < 1000; j++) {
       if(condition) {
            // break two nested enclosing loops
            break(2);
       }
   }
}
DaBler
fuente
Y debajo del capó de hecho está usandogoto :)
iX3
@ iX3 Puedo usar el ensamblador en línea y la instrucción jmp si eso ayuda.
DaBler
@DaBler, no me di cuenta de que eras el autor de esa biblioteca. Mi comentario no pretendía ser una retroalimentación, sino señalar que esta biblioteca utiliza el mismo método que la respuesta aceptada . Con suerte, su comentario fue una broma porque creo que usar una función de idioma (incluso goto) es mucho más preferible que el ensamblaje en línea (específico de la máquina, más fácil de cometer un error, más difícil de leer, ...).
iX3
3
for(int i = 0; i < 1000; i++) {
   for(int j = 0; j < 1000; i++) {
       if(condition) {
            goto end;
   }
} 

end:
chikuba
fuente
3

Si necesita los valores de i y j, esto debería funcionar pero con menos rendimiento que otros

for(i;i< 1000; i++){    
    for(j; j< 1000; j++){
        if(condition)
            break;
    }
    if(condition) //the same condition
        break;
}
Ali Eren Çelik
fuente
Tenga en cuenta que si la condición depende de, jentonces el valor de la condición debe almacenarse de alguna manera para que esto siga funcionando.
SuperBiasedMan
1
Tiene razón, pero después de la pausa , el valor de j no cambia y también lo es el valor de la condición.
Ali Eren Çelik
Esta es una solución rota y no es válida en general. Cualquiera de j no está definida fuera de su bucle o 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; ... }va a siempre salir del bucle exterior después de la primera iteración del bucle interno.
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;
        }
    }
}

Romperá ambos bucles.

Khurram Ijaz
fuente
-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;
}
Berlín
fuente
Básicamente, estás diciendo que debería (1) hacer un montón de llamadas a funciones adicionales y luego (2) girar por el resto del tiempo cuando se conditionvuelve falso. Ah, y el segundo bucle se ejecutará para siempre porque se incrementa en ilugar de j, ¡uy ...
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);
guga
fuente