Dos formas de cambiar el flujo de un bucle
La condición de un bucle decide cuándo termina, pero a veces la respuesta real aparece en mitad del cuerpo. Estás buscando en un array y encuentras el elemento en la tercera posición: ¿para qué revisar los otros 997? O estás procesando una lista y una entrada está en blanco: sáltala y sigue.
C tiene una palabra clave para cada caso:
break- abandona el bucle ahora. La ejecución sigue en la primera sentencia después de él.continue- abandona solo esta pasada. Pasa a la siguiente.
El primer bucle imprime 1 2 3 4 y se detiene. El segundo imprime 1 2 3 4 6 7 8 9 10: se saltó un valor y siguió adelante.
break en un bucle
El uso canónico es una búsqueda que se detiene en cuanto tiene éxito:
Como found se asigna antes del break, el código posterior al bucle puede distinguir entre "lo encontré" y "se acabaron los elementos". Ese emparejamiento - una variable de resultado más un break - es el modismo estándar de búsqueda en C. El propio contador del bucle no sirve después cuando se declara en el encabezado, ya que sale de ámbito en la llave de cierre.
break siempre sale de un bucle: el for, while, do-while o switch más cercano que lo encierra.
continue en un bucle
continue es para las entradas que deberían saltarse en lugar de detener el trabajo:
A dónde salta continue depende del bucle:
for -> a la parte de actualizacion del encabezado (el contador igual avanza)
while -> a la comprobacion de la condicion (nada mas del cuerpo se ejecuta)
do-while -> a la comprobacion de la condicion, abajo
Esa diferencia no es académica. En un bucle for, continue nunca puede saltarse el incremento del contador, porque el incremento está en el encabezado. En un while sí puede:
/* BUG: continue se salta i++, asi que esto se cuelga en el primer numero par */
int i = 0;
while (i < 10) {
if (i % 2 == 0) {
continue;
}
printf("%d ", i);
i++;
}
O mueves i++ por encima del continue, o lo escribes como un bucle for, donde el encabezado hace imposible equivocarse.
un break en un switch no es un break del bucle
break termina el bucle o el switch que lo encierra más de cerca, lo que esté más próximo. Pon un switch dentro de un bucle y cada break dentro de él pertenece al switch:
El comando q imprime su mensaje y el bucle sigue corriendo a través de cc. Si salir debía terminar el bucle, ese break no lo hizo. Las soluciones son una bandera, un goto, o mover el bucle a una función y usar return: todas se muestran abajo.
Escapar de bucles anidados
Un solo break abandona un nivel. Dentro de dos bucles anidados solo termina el interno, y el externo empieza su siguiente pasada como si nada hubiera pasado.
C no tiene break 2 ni un break con etiqueta. Tres opciones honestas:
Una bandera. Portable, evidente y un poco ruidosa:
La bandera aparece en dos sitios - la condición externa y la asignación - y ese es el costo. Con tres niveles de anidamiento se vuelve genuinamente desagradable.
goto. El salto tan denostado de C, y este es el único caso en el que los programadores de C con experiencia lo usan sin pedir disculpas:
Un goto hacia adelante a una etiqueta justo después de los bucles hace exactamente lo que haría un break con etiqueta en otros lenguajes, en una línea y sin ninguna bandera que mantener sincronizada. La reputación que tiene goto se la ganan los saltos hacia atrás y los saltos al medio de otros bloques, que sí producen un flujo de control ilegible. Un único salto hacia adelante para salir de bucles anidados no es eso. El kernel de Linux usa el mismo patrón para sus rutas de limpieza. Úsalo de forma deliberada y con moderación; no dejes que el tabú te empuje a una alternativa de tres banderas que es más difícil de leer.
Una función y return. Normalmente la mejor respuesta, porque una búsqueda merece un nombre:
return deshace todos los bucles de la función, no necesita bandera ni etiqueta, y el código de búsqueda ahora tiene un nombre y puede probarse por separado. Cuando el anidamiento es lo bastante profundo como para que escapar de él sea un problema, eso suele ser una pista de que el bloque quería ser una función de todos modos.
Cuándo ayudan y cuándo estorban
break y continue se ganan su lugar cuando permiten que un bucle diga "este caso ya está resuelto" una vez, cerca del principio, en lugar de envolver todo el cuerpo en un if. Compara:
/* con continue: el trabajo real no queda indentado */
for (int i = 0; i < n; i++) {
if (!isValid(a[i])) continue;
if (isDuplicate(a[i])) continue;
process(a[i]);
}
/* sin el: cada guarda anade un nivel */
for (int i = 0; i < n; i++) {
if (isValid(a[i])) {
if (!isDuplicate(a[i])) {
process(a[i]);
}
}
}
Estorban cuando hay muchos. Un bucle con cinco break dispersos y tres continue tiene una condición de salida que no está escrita en ninguna parte: quien lo lee tiene que simular el cuerpo entero para saber cuándo se detiene. Dos pautas que aguantan bien: mantén juntas las guardas con continue al principio del cuerpo, y si un bucle tiene más de uno o dos break, plantéate si la condición del encabezado debería haber hecho ese trabajo.
Dos trampas menores. Un continue en un do-while salta a la comprobación de abajo, que es lo siguiente de todos modos: inofensivo, pero sorprende. Y un break fuera de cualquier bucle o switch es un error de compilación, que es el único fallo de esta página que el compilador atrapa por ti.
Preguntas frecuentes
¿Cuál es la diferencia entre break y continue en C?
break termina el bucle por completo y la ejecución sigue después de él. continue abandona solo la pasada actual y salta a la siguiente: a la actualización en un bucle for, o directamente a la comprobación de la condición en un while o un do-while.
¿Cómo salgo de un bucle anidado en C?
Un solo break abandona únicamente el bucle más interno. Para salir de ambos, o bien pones una bandera y la compruebas en la condición del bucle externo, o usas goto para saltar a una etiqueta después de los bucles, o - normalmente lo más limpio - mueves los bucles a una función y haces return.
¿break sale del bucle o solo del switch?
De lo que lo encierre más de cerca. Un break dentro de un switch que está dentro de un bucle termina solo el switch; el bucle continúa. Para salir del bucle desde dentro de un switch necesitas una bandera, un goto o un return.
¿Por qué continue provoca un bucle infinito en mi while?
Porque continue salta a la condición y se salta el resto del cuerpo, incluido el incremento del contador si está al final. En un bucle for la actualización vive en el encabezado, así que siempre se ejecuta; en un while, mueve la actualización antes del continue o usa un for.