Saltar al contenido

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.

pseudocodigo
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.

pseudocodigo
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.

pseudocodigo
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?

BucleCuándo compruebaVueltas mínimasSe usa cuando
whileAntes de cada vueltaCeroNo se sabe cuántas repeticiones harán falta y puede que ninguna
do/whileDespués de cada vueltaUnaNo se sabe cuántas, pero hay que ejecutar el cuerpo al menos una vez (pedir y validar un dato)
forAntes de cada vueltaCeroEl 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.
pseudocodigo
// 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.

pseudocodigo
// 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 10

El 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