CodeGym /Cursos /C++ SELF /Bucle while en C++

Bucle while en C++

C++ SELF
Nivel 4, Lección 1
Disponible

1. Familiarización con los bucles

Cuando empiezas a programar puede parecer lógico: «Pues tengo que imprimir 1, 2, 3… así que escribiré tres cout». Esto funciona exactamente hasta que hace falta imprimir 1…100 o repetir una acción hasta que la entrada sea correcta. En ese momento el copiar y pegar se convierte en un desastre: arreglarás el error en 100 sitios y tus ojos empezarán a odiar la pantalla.

El bucle resuelve este problema de forma simple: en lugar de «repetir a mano» describes la regla de repetición. Si lo simplificas mucho, el bucle es un acuerdo con el ordenador: «Te doy una condición y un cuerpo; repite con cuidado mientras la condición sea verdadera». Y el ordenador responde: «Ah, por fin una tarea sensata».

Bucle en la vida real: Mientras Barney esté en el bar — Moe lo echa.

Sintaxis de while y orden de ejecución

Es importante hacerse amigo del while a nivel de «cómo se ejecuta realmente», de lo contrario escribirás bucles que o bien no se ejecutan o bien se ejecutan para siempre. La buena noticia: la regla es muy sencilla.

Forma del bucle:

while (condición) {
    // cuerpo del bucle
}
Forma general del bucle while en C++

Significado: antes de cada ejecución del cuerpo se evalúa la condición. Si es verdadera (true) — se ejecuta el cuerpo. Si es falsa (false) — el bucle termina (o ni siquiera comienza).

Mini‑ejemplo «cuenta atrás»:

#include <iostream>

int main() {
    int x = 3;

    while (x > 0) {
        std::cout << x << '\n';  // 3, luego 2, luego 1
        x = x - 1;
    }

    std::cout << "Go!\n";        // Go!
}

Aquí ocurre algo muy «honesto»: mientras x > 0, imprimimos x y lo decrementamos. En cuanto x llegue a 0, la condición será falsa y el bucle se detendrá.

Fíjate en una idea importante: while puede no ejecutarse ni una sola vez. Por ejemplo:

#include <iostream>

int main() {
    int x = 0;

    while (x > 0) {
        std::cout << "Inside\n";
    }

    std::cout << "Outside\n"; // Outside
}

Esto no es un bug ni una «rareza de C++». Es lógica normal: si la condición es falsa desde el principio, no hay nada que ejecutar.

2. Tres partes de un buen while: preparación, condición, paso

La mayoría de los bucles razonables (es decir, que terminan) con while se pueden descomponer mentalmente en tres partes. Y eso ayuda mucho a encontrar errores.

Antes del bucle suele haber una preparación: fijamos los valores iniciales. En la cabecera del while está la condición de continuación. Y dentro del cuerpo debe haber un paso que nos aproxime al momento en que la condición sea falsa.

Es útil tener esta tabla en la cabeza:

Parte Dónde está Ejemplo Para qué sirve
Preparación antes del bucle
int i = 1;
fijar el inicio
Condición en while (...)
i <= n
decidir si continuamos
Paso dentro del cuerpo
i = i + 1;
«moverse» hacia la finalización

Veamos la tarea clásica: calcular la suma de los números de 1 a n.

#include <iostream>

int main() {
    int n = 0;
    std::cin >> n;

    int i = 1;        // preparación
    int sum = 0;      // preparación

    while (i <= n) {  // condición de continuación
        sum = sum + i;
        i = i + 1;    // paso hacia la finalización
    }

    std::cout << sum << '\n';
}

Aquí es fácil «leer» la idea: mientras i no haya llegado a n, añadimos i a la suma y aumentamos i. El paso garantiza que algún día i será n + 1, la condición i <= n será falsa y el bucle se detendrá.

3. Invariante del bucle: el «juramento» interno

La palabra «invariante» suena como el nombre de un jefe en un RPG, pero en la práctica es algo muy sencillo. Un invariante es una afirmación que permanece verdadera en cada iteración (en cada «vuelta» del bucle). Sirve no para matemáticas sino para autoverificación: «¿Estoy haciendo realmente lo que creo?»

Tomeos la suma 1..n. En ese bucle un invariante conveniente sería: «Antes de cada iteración sum contiene la suma de los números de 1 a i - 1». Esta frase parece pedante, pero inmediatamente te protege de errores típicos: si por accidente empiezas con i = 0 o te olvidas de i = i + 1, el invariante dejará de ser cierto (o no podrás explicar por qué lo es), y entonces la lógica está rota.

Veamos con un n pequeño, = 3, y comprobemos el invariante «a mano»:

  • antes de entrar en el bucle: i = 1, sum = 0. «Suma de 1 a 0» es 0. El invariante es cierto.
  • después de la primera iteración: añadimos 1, queda sum = 1, aumentamos i = 2. Ahora «suma de 1 a 1» es 1. Cierto.
  • después de la segunda: sum = 3, i = 3. «suma de 1 a 2» es 3. Cierto.
  • después de la tercera: sum = 6, i = 4. «suma de 1 a 3» es 6. Cierto. Luego i <= n se convierte en 4 <= 3 → false, el bucle se detiene.

El invariante es tu brújula interna. Si la brújula empieza a mentir, no estás en el bosque sino en un bucle sin paso.

4. Patrones útiles de while en ejemplos cortos

Ahora practicaremos con tareas que aparecen con frecuencia. Aquí el objetivo no es «resolver la tarea» sino ver el patrón repetible: preparación, condición, paso.

Conteo de dígitos en un número

A veces el «paso hacia la finalización» no es incrementar un contador sino reducir el objeto del problema.

#include <iostream>

int main() {
    int n = 0;
    std::cin >> n;

    int digits = 0;

    while (n > 0) {
        digits = digits + 1;
        n = n / 10;          // paso: reducimos el número
    }

    std::cout << digits << '\n';
}

Aquí es importante que n vaya haciéndose más pequeño: 1234 → 123 → 12 → 1 → 0. Y el bucle termina.

Si introduces 0, el bucle no se ejecutará y se imprimirá 0. Esto es lógico, pero a veces se desea considerar que el número 0 tiene «un dígito». Es un ejemplo de cómo los requisitos afectan la lógica del bucle —hoy no profundizamos, solo observamos el comportamiento.

Búsqueda del primer divisor sin break

Aún no hemos tratado break (vendrá más adelante), así que haremos el ejemplo sin salida prematura: usando una «bandera» de resultado.

#include <iostream>

int main() {
    int n = 0;
    std::cin >> n;

    int d = 2;
    int first_divisor = 0;

    while (d <= n && first_divisor == 0) {
        if (n % d == 0) {
            first_divisor = d;
        }
        d = d + 1;
    }

    std::cout << first_divisor << '\n';
}

Aquí la condición de continuación es compuesta: «recorremos divisores mientras no lleguemos a n y mientras no hayamos encontrado un divisor». Es un buen ejemplo de que while no tiene que ser «exactamente N veces»: puede parar cuando se alcanza el objetivo.

Lectura de números hasta un valor de parada

Este es un escenario muy real: leemos números mientras el usuario no introduzca 0 (o -1, o cualquier otro valor‑señal).

#include <iostream>

int main() {
    int x = 0;
    std::cin >> x;

    int sum = 0;

    while (x != 0) {
        sum = sum + x;
        std::cin >> x;       // paso: leemos el siguiente valor
    }

    std::cout << sum << '\n';
}

Aquí el «paso hacia la finalización» es la nueva lectura, que potencialmente puede ser 0 y detener el bucle. Es importante notar: el paso puede ser cambiar la variable mediante cin.

5. Bucles infinitos típicos: cómo aparecen y cómo «curarlos»

Un bucle infinito no es siempre malo (a veces se pretende), pero para el principiante la infinitud suele significar: «olvidé el paso» o «la condición está mal formulada». Es decir, el programa no se ha «colgado porque C++ es complejo», sino que hace honestamente lo que le pediste… solo que le pediste eternidad.

Un dato menor del mundo de la estandarización: el comité de C++ incluso discute «bucles infinitos triviales» como un caso formal del comportamiento de los programas.
Nosotros seremos más prácticos: aprenderemos a encontrar la infinitud en tu código antes de que ella te encuentre a ti.

Error n.º 1: la variable de la condición no cambia

Mira qué sencillo es «romper» un bucle:

#include <iostream>

int main() {
    int x = 3;

    while (x > 0) {
        std::cout << x << '\n';
        // x = x - 1;  // olvidamos el paso
    }
}

La condición x > 0 depende de x, pero x no cambia. Así que la condición siempre es verdadera. Resultado: impresión infinita de «3».

La cura es trivial: restaurar el paso (x = x - 1;). Pero un hábito útil es antes de ejecutar el bucle preguntarte «qué cambia en una iteración y por qué eso acerca a la finalización».

Error n.º 2: punto y coma accidental ; después de while

Este es uno de los errores más traicioneros porque a simple vista casi no se ve. Así:

#include <iostream>

int main() {
    int x = 3;

    while (x > 0); {          // <- ATENCIÓN: punto y coma extra
        std::cout << x << '\n';
        x = x - 1;
    }
}

¿Qué pasa? while (x > 0); — es un bucle con cuerpo vacío. Girará sin hacer nada. Y el bloque { ... } que viene después es simplemente un bloque normal que se ejecutará una vez (después de que el bucle termine... pero no terminará, porque dentro del bucle x no cambia).

Para no atrapar este error, en los ejemplos didácticos siempre escribir el cuerpo con llaves y coloca la { en la siguiente línea para que el ; sea más visible.

Error n.º 3: «hay paso, pero no es el correcto»

A veces honestamente escribes un paso… pero cambias la variable equivocada, la que no afecta a la condición.

#include <iostream>

int main() {
    int x = 3;
    int y = 0;

    while (x > 0) {
        y = y + 1;           // el paso cambia y, pero la condición depende de x
        std::cout << y << '\n';
    }
}

Esto también es infinitud: x sigue siendo 3.

Una técnica útil: anota las variables que participan en la condición (x) y comprueba que se modifican en el cuerpo de manera que la condición llegue a ser falsa.

Error n.º 4: bucle de lectura sin nueva lectura

Una situación muy habitual: quieres leer muchos números pero te olvidas de leer el «siguiente».

#include <iostream>

int main() {
    int x = 0;
    std::cin >> x;

    while (x != 0) {
        std::cout << x << '\n';
        // std::cin >> x;     // olvidamos actualizar x
    }
}

Si x no era 0, el bucle imprimirá el mismo número una y otra vez indefinidamente. En bucles de lectura el «paso» suele ser una nueva lectura con cin >> ... o un cambio del valor leído.

6. Mini‑ejemplo y diagrama de flujo de while

Para que los ejemplos no sean un conjunto de programas sueltos, acordemos: hacemos una aplicación de consola simple que recoge estadísticas de los números introducidos. Hoy añadiremos el mecanismo principal: repetir la lectura hasta la orden de parada.

Idea: el usuario introduce números (por ejemplo, «puntos por ronda»), y 0 significa «ya basta». Contamos la suma, la cantidad y el valor máximo. Aún no usamos arrays ni vectores (vendrán más tarde), así que guardamos solo los agregados.

#include <iostream>

int main() {
    int x = 0;
    std::cin >> x;

    int sum = 0;
    int count = 0;
    int max_value = 0;

    while (x != 0) {
        sum = sum + x;
        count = count + 1;

        if (x > max_value) {
            max_value = x;
        }

        std::cin >> x;
    }

    std::cout << "count=" << count << '\n';
    std::cout << "sum=" << sum << '\n';
    std::cout << "max=" << max_value << '\n';
}

Si introduces 5 2 9 0, el programa imprimirá algo como:

count=3
sum=16
max=9

Aquí se ve claramente cómo while encaja con lo que ya conoces: variables, if, comparaciones, entrada/salida. Y esto, en esencia, es uno de los escenarios «reales» más frecuentes para usar bucles.

Diagrama de flujo: cómo piensa while

Para fijar definitivamente el orden de trabajo, es útil representar while como un esquema simple. No es magia, sino un autómata muy predecible:

flowchart TD
    A[Inicio] --> B[Evaluar condición]
    B -->|false| E[Salida del bucle]
    B -->|true| C[Ejecutar cuerpo]
    C --> D[Volver a la comprobación]
    D --> B

Si alguna vez dudas «por qué el bucle no entra» o «por qué no termina», vuelve a este dibujo y pregúntate: ¿la condición es false? o ¿la condición siempre es true? o ¿falta el paso?

7. Errores típicos al trabajar con while

Error n.º 1: no hay paso hacia la finalización y la condición nunca cambia.
Normalmente esto se manifiesta como «imprime lo mismo» o «el programa se queda colgado». Casi siempre la causa es que la variable de la condición no se modifica en el cuerpo. Se cura con disciplina: antes de ejecutar el bucle, explica en voz alta qué línea hace el paso y por qué la condición llegará a ser falsa.

Error n.º 2: punto y coma extra después de while (condición);.
Este error es especialmente desagradable porque el compilador puede no advertirlo: la sintaxis es formalmente correcta. Pero la lógica cambia radicalmente: el bucle se convierte en vacío y el bloque que sigue se ejecuta por separado. La costumbre de escribir el cuerpo con { ... } y formatear cuidadosamente reduce mucho la probabilidad de tropezar con esta «pared invisible».

Error n.º 3: límite incorrecto (< en lugar de <= o al revés).
En while esto se nota como «una iteración de más/menos». Para no adivinar, es útil repasar mentalmente los dos primeros valores y el último esperado. Si quieres incluir n en la suma, la condición debe ser i <= n. Si no quieres incluirlo — i < n. La elección del signo no es cosmética, es semántica.

Error n.º 4: en bucles de lectura olvidaste actualizar el valor leído.
Si lees x antes del bucle y dentro no haces otra std::cin >> x, el bucle trabajará con el mismo valor una y otra vez. En un bucle «leer muchos valores» el paso suele ser la lectura repetida: sin ella el bucle no avanza.

Error n.º 5: el paso cambia la variable equivocada.
A veces parece que «sí que cambio algo», pero la condición depende de otra variable. Se soluciona con un truco sencillo: subraya las variables que aparecen en la condición while (...) y asegúrate de que al menos una de ellas cambia de forma que la condición llegue a ser falsa. Si ninguna lo hace — casi con seguridad tienes una máquina de movimiento perpetuo (y la patente aún no la han concedido).

1
Tarea
C++ SELF, nivel 4, lección 1
Bloqueada
Lanzamiento del cohete
Lanzamiento del cohete
1
Tarea
C++ SELF, nivel 4, lección 1
Bloqueada
Hucha hasta la palabra de parada
Hucha hasta la palabra de parada
1
Tarea
C++ SELF, nivel 4, lección 1
Bloqueada
Carga de la batería a una potencia
Carga de la batería a una potencia
1
Tarea
C++ SELF, nivel 4, lección 1
Bloqueada
Comprobación honesta de si es primo
Comprobación honesta de si es primo
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION