Menu

Bucles while y do while en C#: sintaxis, lectura de entrada y trampas

Cómo funcionan los bucles while y do while en C#: la condición comprobada antes o después del cuerpo, leer la entrada hasta un valor centinela o hasta el final, while (true) con break, y los errores de bucle infinito en los que cae mucha gente.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

Un bucle while repite su cuerpo mientras una condición siga siendo verdadera. Úsalo cuando no sabes de antemano cuántas iteraciones necesitas: sigue hasta que un saldo llegue a un objetivo, una cola se vacíe o se acabe la entrada.

Salida:

Year 1: 1070.00
Year 2: 1144.90
Year 3: 1225.04
Year 4: 1310.80
Year 5: 1402.55
Year 6: 1500.73
Goal reached after 6 years

La condición se comprueba antes de cada iteración, incluida la primera. Si savings ya alcanzara el objetivo, el cuerpo no se ejecutaría nunca y el programa imprimiría "after 0 years". El bucle depende de que el cuerpo cambie algo que lee la condición; aquí savings crece cada año hasta que savings < goal pasa a ser falso.

do while: ejecutar al menos una vez

Un bucle do while lleva la prueba al final, así que el cuerpo siempre se ejecuta al menos una vez:

Salida:

Attempt 1: got 7
Attempt 2: got 4
Attempt 3: got 1
Done after 3 attempts

El primer valor de code solo existe después de que el cuerpo se haya ejecutado una vez, que es justo cuando encaja un do while. Hay dos detalles de sintaxis que pillan a la gente:

  • El punto y coma después de while (code != 1) es obligatorio. Omitirlo es un error de compilación.
  • Las variables que usa la condición deben declararse antes de do. Una variable declarada dentro de las llaves está fuera de ámbito cuando se evalúa la condición, así que do { int code = ...; } while (code != 1); no compila.

El mismo bucle escrito con while necesita o bien una primera llamada duplicada antes del bucle, o bien un valor inicial ficticio que fuerce la primera pasada. do while expresa directamente "prueba, y luego decide si vuelves a probar".

Leer la entrada hasta un centinela

Leer líneas hasta una palabra de parada, o hasta que termine la entrada, es el bucle while de manual. Console.ReadLine() devuelve null cuando no hay más entrada, así que prueba las dos cosas:

Salida:

skipping "abc": not a number
3 amounts, total 49.50

(line = Console.ReadLine()) != null asigna la línea siguiente y la prueba en una sola expresión; los paréntesis alrededor de la asignación son obligatorios porque != tiene más precedencia que =. El bucle se detiene en done, así que el 99 que va después nunca se lee. decimal.TryParse rechaza abc sin lanzar una excepción, y continue salta a la línea siguiente. Sin la comprobación de null, llegar al final de la entrada pasaría null a TryParse para siempre, porque ReadLine sigue devolviendo null.

Un do while encaja con el patrón de preguntar y validar, en el que la pregunta debe aparecer al menos una vez:

Salida:

Enter your age:
"-4" is not a valid age
Enter your age:
"fifteen" is not a valid age
Enter your age:
Age accepted: 15

La pregunta está dentro del bucle, así que se repite después de cada respuesta rechazada, y age se declara antes de do para que el código posterior al bucle pueda usarla. Con un usuario en el teclado, cada respuesta aparece en la consola después de su pregunta; con la entrada redirigida, como aquí, solo se muestra la salida del propio programa.

while (true) con break

A veces el punto de salida natural está en mitad del cuerpo, después de algo de trabajo y antes del resto. Escribe el bucle como while (true) y sal con break:

Salida:

processing: resize photo
processing: send email
stop signal received
1 job(s) left in the queue

Dequeue saca el siguiente trabajo del principio de la cola, y el bucle sale en cuanto ve el marcador de parada, así que el último trabajo se queda en la cola. while (true) no es un mal olor de código cuando la salida es clara y está cerca del principio del cuerpo. Lo es cuando hay varios break repartidos por un cuerpo largo; entonces una condición bool con nombre o un método con return se siguen mejor. La página de break y continue explica cómo salir de bucles anidados.

Bucles que nunca terminan

Un bucle infinito no deseado tiene una de tres causas.

El cuerpo nunca cambia la condición. El contador no se incrementa nunca, o se incrementa la variable equivocada:

int i = 0;
while (i < 5)
{
    Console.WriteLine(i);   // i++ forgotten: prints 0 forever
}

Un punto y coma después de la condición. El punto y coma es todo el cuerpo del bucle, y el bloque de debajo se ejecuta después del bucle (que nunca termina):

while (retries < 3);        // warning CS0642: Possible mistaken empty statement
{
    retries++;
}

Una condición que se pasa de su objetivo. Probar != cuando la variable avanza a saltos puede saltarse el valor de parada. while (x != 10) x += 3; pasa por 0, 3, 6, 9, 12 y sigue de largo sin parar en 10 (solo cae en 10 por casualidad, después de que el int se desborde y dé la vuelta miles de millones de pasos más tarde). Prueba con < o > en lugar de != siempre que el paso no sea 1. Lo mismo vale para los valores double, que rara vez llegan a un objetivo exacto: while (x != 1.0) x += 0.1; nunca termina.

Elegir entre while, do while y for

SituaciónBucle
Número conocido de iteraciones, o un índicefor
Cada elemento de una colecciónforeach
Repetir mientras se cumpla una condición, quizá cero veceswhile
El cuerpo debe ejecutarse una vez antes de que la condición tenga sentidodo while
Prueba de salida en mitad del cuerpowhile (true) con break

Cualquier bucle for puede reescribirse como un bucle while y al revés; la elección depende de cuál pone la lógica del bucle donde el lector la espera. Cuando existen el contador, la prueba y el paso, for los mantiene en una línea. Cuando el bucle lo mueve un estado que cambia dentro del cuerpo, while lo dice.

Preguntas frecuentes

¿Qué diferencia hay entre while y do while en C#?

Un bucle while comprueba su condición antes de cada iteración, así que su cuerpo puede ejecutarse cero veces. Un bucle do { } while (condition); la comprueba después de cada iteración, así que su cuerpo siempre se ejecuta al menos una vez. Usa do while cuando la primera pasada produce el valor que prueba la condición, como leer una entrada y después validarla.

¿Cuál es la sintaxis de un bucle do while en C#?

do { body } while (condition);. Fíjate en el punto y coma después del paréntesis de cierre: es obligatorio, y omitirlo es un error de compilación. La condición puede usar variables asignadas en el cuerpo, pero deben declararse antes del do, porque las llaves del cuerpo son un ámbito aparte.

¿Cómo escribo while (true) en C#?

while (true) { ... } se repite para siempre hasta que algo dentro sale con break, return o una excepción. Es la forma natural cuando la prueba de salida va en mitad del cuerpo, como leer una línea y parar cuando está vacía.

¿Cómo leo la entrada hasta que el usuario escriba una palabra o se acabe la entrada en C#?

Haz el bucle sobre Console.ReadLine(), que devuelve null al final de la entrada: string line; while ((line = Console.ReadLine()) != null && line != "done") { ... }. La asignación dentro de la condición lee la línea siguiente y la prueba en un solo paso.

¿Por qué mi bucle while de C# nunca termina?

Normalmente el cuerpo nunca cambia lo que prueba la condición (un i++ olvidado), o hay un punto y coma justo después de la condición: while (count < 10); es un bucle con el cuerpo vacío que gira para siempre. El compilador avisa del segundo caso con CS0642, Possible mistaken empty statement.

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR