ESTRUCTURAS DE CONTROL - SENTENCIAS WHILE Y DO WHILE
Sentencia
while()
.

Es frecuente encontrar sentencias
for()
en las que hay un número elevado de componentes en las cláusulas de iniciación y actualización. Y también es frecuente hallar sentencias
for()
que se reducen a una cláusula de control: las cláusulas de iniciación y actualización adoptan la forma de sentencias independientes, situadas adecuadamente antes de la sentencia
for()
y dentro del bloque. En tales circunstancias es cómodo emplear una sentencia reducida a la cláusula de control: esta es precisamente la sentencia
while()
, cuya sintaxis es la que se ve a continuación:
while(condición)
{
Bloque;
}
Como cabe esperar,
condición
denota una expresión que se evaluará lógicamente: si su valor es nulo, se entenderá que es falsa; y si su valor es no nulo se entenderá que es verdadera. La palabra reservada
while
significa mientras; mientras
condición
sea verdadera, la sentencia
while()
seguirá iterando (ejecutando las sentencias contenidas en el bloque).
Al llegar a la sentencia
while()
, se evalúa condición. Si su valor es verdadero, se efectúa una iteración, y vuelve a evaluarse condición. Si su valor es falso, se ignora el bucle sin haber efectuado ni siquiera una iteración. No se impone restricción alguna sobre las sentencias contenidas en el bloque. Consiguientemente, se admiten las sentencias de control, y en particular la sentencia
while()
. Por tanto, se admite explícitamente el anidamiento de sentencias
while()
.
Al igual que la sentencia
for(),
while()
es de comprobación anterior (se evalúa la cláusula de control antes de efectuar la primera iteración). Esto sugiere que todo lo que pueda hacerse con una sentencia
for()
será realizable con una sentencia
while()
, y viceversa. Así es. Basta anteponer la cláusula de iniciación de la sentencia
for()
a la sentencia
while()
, e insertar al final del bloque de la sentencia
while()
la cláusula de actualización de la sentencia
for()
. Estas dos sentencias son equivalentes, y la utilización de una u otra será cuestión de comodidad. Es preciso prestar especial atención a la ubicación de las sentencias de actualización dentro del bloque: una situación incorrecta producirá resultados no deseados, y el compilador no detecta este tipo de errores lógicos. La forma segura de utilizar una sentencia
while()
consiste en insertar las sentencias de actualización al final del bloque. Véase un
ejemplo
de utilización de la sentencia
while()
.
Sentencia
do-while()
.

No todas las ocasiones exigen el uso de una sentencia de comprobación anterior; de hecho, es frecuente hallar casos (introducción de datos con verificación de valores, por ejemplo) en los que resulta preferible que se produzca una iteración antes de comprobar si es preciso seguir iterando. Esto es, se precisa una estructura en que la evaluación de la cláusula de control sea
posterior
a la evaluación del bloque. Esta es precisamente la sentencia
do-while()
, representada gráficamente a la izquierda de estas líneas. La sintaxis de esta sentencia es de la forma:
do
{
Bloque;
} while (condición);
Al llegar a esta sentencia, se efectúa una iteración (se ejecuta el contenido del bloque) y se evalúa después la condición de iteración. Si esta condición es verdadera, se efectúa una nueva iteración . En caso contrario, finaliza la ejecución de esta sentencia. Dicho de otra manera, seguiremos iterando mientas se verifique la condición.
La representación gráfica permite comprender fácilmente el flujo de control de esta sentencia. Las sentencias de iniciación deben aparecer antes de la palabra reservada
do
. Las sentencias de actualización pueden situarse al principio del bloque o al final del mismo, según convenga. La posición inicial dará lugar a que el resto del bloque se ejecute después de la actualización; esto puede ser correcto o incorrecto dependiendo de la iniciación efectuada antes de entrar en el bloque. La posición final hará que se evalúe la sentencia de control antes de efectuar la iteración correspondiente a la última actualización; esto puede ser lo deseado o quizá no, dependiendo del caso concreto. En todo caso habrá que prestar especial atención a las actualizaciones. La sentencia
do-while()
resulta de especial utilidad, como decimos, para imponer al usuario unos ciertos límites al insertar datos en un programa. Si el valor insertado está fuera de los límites especificados, se efectúa una nueva iteración que solicita un valor correcto. Como
ejemplo
, véase una nueva versión del juego Mastermind, que se ha utilizado anteriormente como ejemplo en las sentencias
for()
y
while()
.
Ejercicio 1
.- Construir el juego de Mastermind empleando una sentencia
while()
, en lugar de emplear una sentencia
for()
. El juego permitirá un número ilimitado de intentos, y comunicará al usuario el número de intentos que ha necesitado para adivinar el número.
/*
Otra implementación de MASTERMIND.
Este ejercicio muestra el uso de sentencias while()
*/
#include<stdio.h>
#include<time.h>
#include<math.h>
#define maximo 512
void main(void)
{
int numero_buscado = clock() % maximo,numero_dado = 0;
int numero_pregunta = 0;
printf("M A S T E R M I N D\n\n");
printf("He pensado un numero entre 1 y %d.\n\n", maximo);
printf("¿Cuántos intentos necesitas para averiguarlo?\n");
while( numero_dado != numero_buscado)
{
printf("\nIntento número %d : ",++numero_pregunta);
scanf("%d",&numero_dado);
if (numero_dado < numero_buscado)
printf("\nNo, %d es menor que el número que he pensado.\n", numero_dado);
else
if (numero_dado > numero_buscado)
printf("\nNo, %d es mayor que el número que he pensado.\n", numero_dado);
}
printf("\n\nEnhorabuena! Has necesitado %d intentos.",numero_pregunta);
printf("\n\nTerminación normal del programa.\n");
}
/*
RESULTADO
M A S T E R M I N D
He pensado un numero entre 1 y 512.
¿Cuántos intentos necesitas para averiguarlo?
Intento número 1 : 256
No, 256 es menor que el número que he pensado.
Intento número 2 : 384
No, 384 es menor que el número que he pensado.
Intento número 3 : 448
No, 448 es menor que el número que he pensado.
Intento número 4 : 480
No, 480 es mayor que el número que he pensado.
Intento número 5 : 464
No, 464 es menor que el número que he pensado.
Intento número 6 : 472
Enhorabuena! Has necesitado 6 intentos.
Terminación normal del programa.
COMENTARIOS
Obsérvese la simplificación con respecto al programa anterior.
Sería sencillo volver a introducir el límite de intentos. Con todo,
la estructura de comprobación anterior while() no es especialmente
adecuada para un juego, en el cual comprobación de corrección deberá
hacerse después de haber pedido un valor. Utilizaremos, por tanto,
una sentencia do-while().
*/
Ejercicio 2
.- Construir el juego Mastermind empleando sentencias do-while(). Permitir que el usuario determine el alcance máximo, con ciertos límites.
/*
Otra implementación de MASTERMIND.
Este ejercicio muestra la utilización de sentencias do-while().
*/
#include<stdio.h>
#include<time.h>
#include<math.h>
#define MAX_ADMISIBLE 4096
void main(void)
{
int maximo, numero_pregunta;
int numero_buscado, numero_dado, max_preguntas;
printf("M A S T E R M I N D\n\n");
do
{
printf("Indique el alcance máximo (1 < alcance <= %d) : ", MAX_ADMISIBLE);
scanf("%d", &maximo);
} while (maximo < 1 || maximo > MAX_ADMISIBLE);
numero_buscado = clock() % maximo;
max_preguntas = (int)(ceil(log(maximo)/log(2)));
printf("\nHe pensado un numero entre 1 y %d.¿Sabrás cual es en %d intentos?\n\n",
maximo,max_preguntas);
numero_pregunta=1;
do
{
printf("Intento número %d : ",numero_pregunta);
scanf("%d",&numero_dado);
// Si el pringaíllo lo ha encontrado, salimos del bucle!
if (numero_dado == numero_buscado) break;
// En caso contrario, damos la pista correspondiente y seguimos
if (numero_dado < numero_buscado)
printf("\nNo, %d es menor que el número que he pensado.\n", numero_dado);
else
printf("\nNo, %d es mayor que el número que he pensado.\n", numero_dado);
numero_pregunta ++;
} while (numero_pregunta<max_preguntas);
if (numero_dado != numero_buscado)
printf("\n\nJa! Había pensado el %d\n\n", numero_buscado);
else
{
printf("\n\nEnhorabuena! Era el %d!\n\n>Fin<\n\n",numero_buscado);
printf("Has necesitado %d intentos.\n", numero_pregunta);
}
printf("\nTerminación normal del programa.\n");
}
/*
RESULTADO
M A S T E R M I N D
Indique el alcance máximo (1 < alcance <= 4096) : 4096
He pensado un numero entre 1 y 4096.¿Sabrás cual es en 12 intentos?
Intento número 1 : 2048
No, 2048 es mayor que el número que he pensado.
Intento número 2 : 1024
No, 1024 es menor que el número que he pensado.
Intento número 3 : 1536
No, 1536 es menor que el número que he pensado.
Intento número 4 : 1768
No, 1768 es menor que el número que he pensado.
Intento número 5 : 1920
No, 1920 es mayor que el número que he pensado.
Intento número 6 : 1856
No, 1856 es menor que el número que he pensado.
Intento número 7 : 1888
No, 1888 es mayor que el número que he pensado.
Intento número 8 : 1876
No, 1876 es mayor que el número que he pensado.
Intento número 9 : 1866
No, 1866 es menor que el número que he pensado.
Intento número 10 : 1871
No, 1871 es menor que el número que he pensado.
Intento número 11 : 1874
Enhorabuena! Era el 1874!
>Fin<
COMENTARIOS
Recuérdese que hay que respetar las convenciones
del código fuente en lo tocante a sangrados, espacios etc.
¿Sería tan comprensible el código si estuviera alineado
a la izquierda, sin sangrados?
El operador || (q. v.) denota la disyunción lógica, OR.
*/
Ejercicios propuestos
-
Ejercicio 0403r01.-
Escribir un programa que lea, uno tras otros, todos los bytes de un archivo. El programa debe mostrar el número de bytes que hay en el archivo.
-
Ejercicio 0403r02.-
Escribir un programa que lea todos los bytes de un archivo de texto y los escriba por orden inverso en un archivo cuyo nombre se el inverso del original (mantener la extensión!).
-
Ejercicio 0403r03.-
Escribir un programa que lea las líneas de un archivo de texto y muestre el recuento en pantalla.
-
Ejercicio 0403r04.-
Escribir un programa que lea todas las líneas de un archivo de texto y las almacene internamente en una lista de cadenas, para después mostrarlas en pantalla por orden inverso al original.
-
Ejercicio 0403r05.-
Se dispone de un archivo que contiene una lista de líneas de formato delimitado. Se pide construir un programa que las lea para después escribirlas en un archivo de formato encolumnado.
-
Ejercicio 0403r06.-
Se dispone de un archivo que contiene una lista de líneas de formato encolumnado. Se pide construir un programa que las lea para después escribirlas en un archivo de formato delimitado.
-
Ejercicio 0403r07.-
Construir una función que admita un mensaje de petición y dos números enteros. La función sólo retornará cuando el usuario inserte un número entero comprendido entre los dos dados.
-
Ejercicio 0403r08.-
Construir una función de acceso a un programa. La función leerá de un archivo una tabla codificada (con dos columnas) formada por nombres de usuario y contraseñas. Esta función sólo permitirá acceder al programa a los usuarios que proporcionen un nombre y contraseña de los indicados en la lista.