Bucles
Cómo se repite un grupo de instrucciones sin escribirlo mil veces: el while, el do/while y el for, cuándo conviene cada uno, las instrucciones break y continue, y el bucle infinito.
Qué es un bucle
Un programa que tuviera que corregir cien preguntas y solo dispusiera de secuencia y condicionales necesitaría cien copias del mismo trozo de código. Eso es inviable, y además el número de repeticiones casi nunca se sabe de antemano: depende de cuántas preguntas tenga el test. Para eso están los bucles, que son la tercera estructura básica: un grupo de instrucciones que se repite mientras se cumpla una condición.
La analogía útil es la de una instrucción con vuelta atrás. El programa entra, ejecuta las instrucciones del cuerpo, y en vez de continuar hacia abajo vuelve al principio y se pregunta si tiene que repetir. Solo cuando la respuesta es no sigue adelante.
- Cuerpo del bucle: las instrucciones que se repiten, encerradas entre llaves.
- Condición de continuación: la expresión booleana que decide si se da otra vuelta.
- Iteración: cada una de las vueltas completas que da el bucle.
- Variable de control: la que interviene en la condición y va cambiando en cada vuelta. Sin ella el bucle no puede terminar nunca.
Dentro de un bucle aparecen constantemente dos figuras que conviene reconocer. Un contador es una variable que aumenta de uno en uno para llevar la cuenta de las vueltas. Un acumulador es una variable que va sumando valores para obtener un total, y siempre hay que inicializarla a cero antes de entrar en el bucle: si se inicializa dentro, se reinicia en cada vuelta y al final solo queda el último valor.
Todo bucle necesita tres piezas: una variable de control inicializada antes de entrar, una condición que la consulte y una instrucción dentro del cuerpo que la modifique. Si falta la tercera, el bucle no termina jamás.
Para el examen
Las tres piezas: variable de control inicializada, condición que la consulte e instrucción que la modifique
El acumulador: se inicializa a cero ANTES del bucle, nunca dentro
El bucle while
El while es el bucle más elemental y se lee como «mientras se cumpla esto, repite aquello». Comprueba la condición ANTES de cada vuelta, incluida la primera, de modo que si la condición es falsa desde el principio el cuerpo no se ejecuta ni una sola vez.
entero temasPendientes = 3
while (temasPendientes > 0) {
escribir("Queda por repasar el tema numero " + temasPendientes)
temasPendientes--
}
escribir("No queda ningun tema pendiente")- Línea 1: la variable de control se inicializa ANTES del bucle. Si no existiera ya, la condición de la línea 3 no podría evaluarse.
- Línea 3: se comprueba la condición. 3 es mayor que 0, así que se entra en el cuerpo.
- Línea 4: se escribe el aviso con el valor actual, 3.
- Línea 5: se resta uno a la variable de control. Esta línea es la que permite que el bucle acabe algún día.
- Al llegar a la llave de cierre, el programa vuelve a la línea 3 y repite la comprobación con el valor 2, después con el 1, y después con el 0.
- Con el valor 0 la condición ya es falsa: el cuerpo no se ejecuta y el programa salta a la línea 8.
El bucle da por tanto tres vueltas, con los valores 3, 2 y 1. Es útil comprobar qué habría pasado si «temasPendientes» hubiera valido cero de entrada: la condición sería falsa en la primera comprobación y el cuerpo no se ejecutaría nunca. Ese detalle es justo lo que distingue al while del bucle siguiente.
El while comprueba primero y ejecuta después, así que su cuerpo puede ejecutarse cero veces. Es el bucle indicado cuando no se sabe cuántas vueltas harán falta.
Para el examen
Cuándo comprueba: ANTES de cada vuelta
Si la condición es falsa de entrada: el cuerpo se ejecuta cero veces
El bucle do/while
El do/while es el mismo bucle con la comprobación al final. Ejecuta el cuerpo y solo entonces se pregunta si repite. La consecuencia es la que se pregunta siempre: el cuerpo de un do/while se ejecuta al menos una vez, aunque la condición sea falsa desde el principio.
entero respuesta
do {
escribir("Elige el bloque a estudiar (1 a 4): ")
respuesta = leerNumero()
} while (respuesta < 1 || respuesta > 4)
escribir("Has elegido el bloque " + respuesta)- Línea 3: la palabra do abre el cuerpo sin comprobar nada. Se entra directamente.
- Líneas 4 y 5: se pide el dato al usuario y se guarda en la variable.
- Línea 6: ahora sí se evalúa la condición. Si el número está fuera del rango válido, se vuelve al do y se pide otra vez.
- Si el número es correcto, la condición es falsa y el bucle termina.
Este ejemplo explica por sí solo para qué sirve el do/while: pedir un dato y validarlo. Preguntar hay que preguntar sí o sí al menos una vez, porque sin el dato no hay nada que comprobar. Con un while habría que duplicar la petición antes del bucle para que la primera comprobación tuviera sentido.
Conviene fijarse también en que la condición del ejemplo es de repetición, no de aceptación: se repite mientras el dato sea inválido. Invertirla por descuido y escribir la condición de validez es un error frecuente, porque produce un bucle que se repite justo cuando el dato ya es correcto.
El while puede ejecutar su cuerpo cero veces y el do/while lo ejecuta como mínimo una. Esa es la única diferencia entre los dos, y es la pregunta habitual de examen.
Para el examen
Cuándo comprueba: al FINAL de cada vuelta
Consecuencia: el cuerpo se ejecuta al menos una vez
Uso típico: pedir y validar un dato
El bucle for
El for está pensado para el caso más frecuente de todos: repetir un número conocido de veces. No aporta nada que no se pueda hacer con un while, pero reúne en una sola línea las tres piezas que en un while andan repartidas, con lo que es más difícil olvidarse de alguna.
for (entero i = 1; i <= 5; i++) {
escribir("Corrigiendo la pregunta numero " + i)
}
// El mismo bucle escrito con while:
entero i = 1
while (i <= 5) {
escribir("Corrigiendo la pregunta numero " + i)
i++
}- Primera parte, entero i = 1: la inicialización. Se ejecuta una sola vez, al empezar.
- Segunda parte, i <= 5: la condición. Se comprueba antes de cada vuelta, igual que en el while.
- Tercera parte, i++: el incremento. Se ejecuta al terminar cada vuelta, justo antes de volver a comprobar la condición.
- El cuerpo se ejecuta con i valiendo 1, 2, 3, 4 y 5. Cuando i llega a 6 la condición falla y el bucle termina.
Las dos versiones del ejemplo hacen exactamente lo mismo, y compararlas es la mejor forma de entender el for: la inicialización que en el while va antes, la condición que va en el paréntesis y el incremento que va al final del cuerpo, aquí están las tres juntas en la cabecera.
La variable de control de un for suele llamarse i por convención, de índice, y si hacen falta más se sigue con j y k. Además, la mayoría de lenguajes ofrecen una variante llamada for-each o «para cada», que recorre todos los elementos de una colección sin manejar índices: se usa cuando hay que pasar por todos los elementos y no interesa la posición de cada uno.
El for agrupa inicialización, condición e incremento en su cabecera. Es equivalente a un while, no más potente: se elige por comodidad cuando el número de repeticiones se conoce de antemano.
Para el examen
Sus tres partes: inicialización, condición e incremento
Cuándo se ejecuta cada una: la inicialización una vez, la condición antes de cada vuelta y el incremento al final
Ejemplo: for (i = 1; i <= 5; i++) da exactamente cinco vueltas
Cuándo usar cada bucle
Los tres bucles son intercambiables: cualquier cosa que se haga con uno se puede hacer con los otros dos. La elección es de claridad, y responde a dos preguntas: ¿se sabe cuántas vueltas hay que dar?, y ¿hay que ejecutar el cuerpo al menos una vez?
| Bucle | Cuándo comprueba | Vueltas mínimas | Se usa cuando |
|---|---|---|---|
| while | Antes de cada vuelta | Cero | No se sabe cuántas repeticiones harán falta y puede que ninguna |
| do/while | Después de cada vuelta | Una | No se sabe cuántas, pero hay que ejecutar el cuerpo al menos una vez (pedir y validar un dato) |
| for | Antes de cada vuelta | Cero | El número de repeticiones se conoce de antemano, o hay que recorrer algo posición a posición |
En la práctica, la regla que sirve casi siempre es esta: si se puede contar, for; si depende de una condición que puede no cumplirse nunca, while; y si hay que hacerlo una vez antes de poder decidir, do/while.
Un bucle se llama determinista cuando el número de vueltas está fijado antes de empezar, que es el caso típico del for, e indeterminista cuando depende de algo que ocurre dentro, como la respuesta de un usuario o la aparición de un dato buscado.
Para el examen
Si se puede contar: for
Si depende de una condición que puede no cumplirse nunca: while
Si hay que ejecutar al menos una vez: do/while
En capacidad: los tres son intercambiables
Break y continue
A veces conviene alterar el recorrido normal de un bucle sin esperar a que la condición falle. Para eso existen dos instrucciones que se confunden entre sí con mucha facilidad, y la diferencia se pregunta a menudo.
- break sale del bucle inmediatamente. Se abandona la vuelta actual y no se dan más: el programa continúa por la primera línea que haya después del bucle.
- continue abandona solo la vuelta actual y salta a la siguiente. El bucle no termina: se da por concluida esta iteración y se vuelve a comprobar la condición.
// BREAK: buscar el primer tema pendiente y dejar de buscar
for (entero i = 1; i <= 33; i++) {
if (estaPendiente(i)) {
escribir("El primer tema pendiente es el " + i)
break
}
}
// CONTINUE: repasar solo las preguntas falladas
for (entero i = 1; i <= 100; i++) {
if (respuestaCorrecta(i)) {
continue
}
escribir("Repasa la pregunta " + i)
}En el primer bucle, en cuanto se encuentra un tema pendiente se escribe y el break corta la búsqueda: no tiene sentido seguir recorriendo los treinta y tres temas si ya se ha encontrado el primero. Sin el break, el bucle seguiría hasta el final y escribiría todos los pendientes, no solo el primero.
En el segundo bucle, cuando la respuesta fue correcta el continue salta directamente a la siguiente pregunta y se salta la línea de escribir. Cuando la respuesta fue incorrecta no se ejecuta el continue, así que el programa llega a la última línea y muestra el aviso. El bucle recorre las cien preguntas en cualquier caso.
break termina el bucle entero; continue termina solo la vuelta en curso. En un bucle anidado, ambos afectan únicamente al bucle más interno en el que están.
Para el examen
break: sale del bucle entero
continue: salta solo la vuelta actual
En bucles anidados: los dos afectan únicamente al bucle más interno
El bucle infinito
Un bucle infinito es el que nunca deja de repetirse porque su condición jamás llega a ser falsa. El programa se queda dando vueltas, deja de responder y consume procesador hasta que alguien lo detiene. Es el error más característico de quien empieza con bucles, y casi siempre tiene una de estas tres causas.
// 1. Olvidar modificar la variable de control
entero i = 1
while (i <= 5) {
escribir(i) // falta el i++: «i» vale 1 para siempre
}
// 2. Modificarla en el sentido equivocado
entero pendientes = 3
while (pendientes > 0) {
pendientes++ // en vez de restar, suma: se aleja del final
}
// 3. Una condicion que no puede volverse falsa
entero i = 1
while (i != 10) {
i += 3 // pasa por 1, 4, 7, 10... y aqui si para,
} // pero con i += 4 saltaria de 9 a 13 y nunca
// seria igual a 10El tercer caso es el más traicionero, porque el bucle parece correcto. La lección práctica es preferir las comparaciones de orden (menor que, mayor o igual que) a las de igualdad exacta en la condición de un bucle: si la variable se pasa de largo, una condición de igualdad no la detiene y una de orden sí.
No todo bucle infinito es un error. A veces se escribe a propósito, con la forma while (true), para un programa que tiene que estar siempre en marcha, como un servidor a la espera de peticiones o el bucle principal de una aplicación. En ese caso la salida se controla desde dentro con un break, y lo que hay que vigilar es que ese break sea alcanzable.
Antes de dar por bueno un bucle, hay que responder a una pregunta: qué instrucción de dentro del cuerpo acerca la condición a hacerse falsa. Si no hay ninguna, el bucle es infinito.
Para el examen
Sus tres causas: no modificar la variable de control, modificarla al revés o una condición inalcanzable
Recomendación en la condición: comparaciones de orden mejor que igualdad exacta
Caso legítimo: while (true) con break, en servidores