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



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

  2. 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!).

  3. Ejercicio 0403r03.- Escribir un programa que lea las líneas de un archivo de texto y muestre el recuento en pantalla.

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

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

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

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

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