¿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

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

Respuestas:


43

Utilizar:

if (condition) {
    i = j = 1000;
    break;
}

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.


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

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

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 

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


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

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:

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

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.


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

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);
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.