jueves, 24 de mayo de 2012

Estructuras de Control III: La Instrucción While

______________________________________________________________________________________________
CICLO WHILE CONTROLADO POR CENTINELA.
______________________________________________________________________________________________
Suponga que usted quiere calcular el promedio de las calificaciones de un alumno. No sabe a priori el número de calificaciones que va a recibir. Incluso puede que tenga que calcular el promedio de varios alumnos con distintas calificaciones cada uno. La instrucción de repetición while es una de las principales estructuras de la programación estructurada. While es similar a if en cuanto a que consta de una condición booleana (o que se convierte explícitamente a una) y tiene un cuerpo de instrucciones que han de realizarse si la condición se evalúa como verdadera. Sin embargo, el cuerpo de while se realiza no una vez sino tantas veces como la condición resulte ser cierta. Presumiblemente, en el cuerpo de instrucciones se modificará la condición en el momento oportuno, aunque formalmente la sintaxis de la instrucción no lo requiere. Así que bien podría crearse un ciclo infinito si la condición permanece verdadera de manera infinita. Por ejemplo, en el caso de calcular el promedio, usted no sabe cuántas calificaciones tiene que recibir. Debe recibir tantas como materias haya cursado el alumno. Cada vez usted debe recibir la calificación, sumar el número recibido a la suma acumulada de las calificaciones y aumentar el contador de calificaciones en 1. Al final el promedio será la suma acumulada de calificaciones dividida entre el número de calificaciones. ¿Pero cuándo dejará el programa de realizar ese cuerpo de instrucciones? La respuesta es que debe de hacerse hasta que usted le indique, mediante el teclado, que el final ha llegado. Una manera simple es indicar en el programa que si la calificación recibida es un número negativo, entonces el fin del programa ha llegado. ¿Por qué una calificación negativa? Porque ningún alumno obtiene una calificación negativa en un curso por muy malo que sea. La menor calificación es 0. Así que si usted teclea un número negativo, ese valor puede ser tomado como la bandera que indique el fin del ciclo while. Esta forma de controlar un ciclo while se llama por centinela. La instrucción o cuerpo de instrucciones se realizará mientras la condición sea verdadera.
Para ver al ciclo while en acción, escriba, compile y ejecute el siguiente programa:

/*++++++++++++++++++++++++++++++++++++++++++
 +                                          +
 + Este programa recibe calificaciones de   +
 + un alumno e imprime su promedio          +
 +                                          +
 +++++++++++++++++++++++++++++++++++++++++++*/

 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 *                                                                   +
 +                           ALGORITMO:                              +
 + Pedir al usuario la calificacion de la primera materia            +
 + Recibe el numero de horas                                         +
 +                                                                   +
 + Mientras la calificacion es un numero > 0                         +
 + Suma la calificacion actual a la suma acumulada de calificaciones +
 + Incrementa el numero de calificaciones en 1                       +
 + Repetir los pasos anteriores hasta que el numero de horas sea     +
 + negativo                                                          +
 +                                                                   +
 + El promedio del alumno es la suma acumulada de calificaciones     +
 + dividida entre el numero de calificaciones                        + 
 +                                                                   +
 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

 #include <stdio.h>
 
 int main()

 {      /* Abre main */
 int materias = 0;
 int calificacion = 0;
 int suma = 0;
 float promedio = 0; 
 /* Declarar antes de usar */
 
 printf("\nEste programa recibe las calificaciones de un alumno ");
 printf("y calcula e imprime el promedio.\n");
 printf("\nIntroduzca la calificacion de la primera materia: (negativo para terminar)\n");
 scanf("%d", &calificacion);
 printf("\nCalificacion = %d", calificacion); 
 
 while ( 0 < calificacion )
 {     /* Abre while */
 suma = suma + calificacion;
 materias = materias + 1;   
 printf("\nIntroduzca la calificacion de la siguiente materia: (negativo para terminar)\n");
 scanf("%d", &calificacion);
 }     /* Cierra while */ 

 if ( 0 != materias )
 promedio = (float)suma/materias;
 else
 promedio = 0;

 printf("\nEl promedio de este estudiante es: %.3f \n", promedio);
 
 }      /* Cierra main */

____________________________________________________________________________________________
Ahora hagamos un análisis del programa línea por línea para revisar cada instrucción

/*++++++++++++++++++++++++++++++++++++++++++
 +                                          +
 + Este programa recibe calificaciones de   +
 + un alumno e imprime su promedio          +
 +                                          +
 +++++++++++++++++++++++++++++++++++++++++++*/

 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 *                                                                   +
 +                           ALGORITMO:                              +
 + Pedir al usuario la calificacion de la primera materia            +
 + Recibe el numero de horas                                         +
 +                                                                   +
 + Mientras la calificacion es un numero > 0                         +
 + Suma la calificacion actual a la suma acumulada de calificaciones +
 + Incrementa el numero de calificaciones en 1                       +
 + Repetir los pasos anteriores hasta que el numero de horas sea     +
 + negativo                                                          +
 +                                                                   +
 + El promedio del alumno es la suma acumulada de calificaciones     +
 + dividida entre el numero de calificaciones                        + 
 +                                                                   +
 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

Estos dos recuadros son un par de comentarios. En C los comentarios empiezan con /* y terminan con */, aunque la mayoría de los compiladores también aceptarán como comentario todo lo que se encuentre a continuación de // y hasta el siguiente salto de línea. En el primer recuadro aparece el propósito general del programa, que es calcular el promedio de calificaciones de un alumno. En el segundo recuadro aparece el algoritmo en seudocódigo. Un algoritmo es una receta que hay que seguir para llevar a cabo una tarea. Los algoritmos para computadoras no admiten ambigüedades. Éste algoritmo en seudocódigo es un mensaje para el programador. De inmediato puede determinar qué hace el programa y decidir si el método le satisface o no. La mayoría de los códigos con los que se encuentre en su vida de programador van a tener pocos comentarios. Ésto se debe a la idea generalizada que tienen muchos programadores de que no hacen falta. Los programas de éste curso sí tienen el algoritmo en seudocódigo al principio, y los que usted escriba también deberían tenerlo.

#include <stdio.h>
 

Casi todos sus programas en C van a llevar este encabezado. Le indica al preprocesador que incluya el contenido del archivo stdio (salida y entrada estándar).

int main()

C es un lenguaje de propósito general. No es un lenguaje visual, tampoco fue diseñado para programar aplicaciones web. En C la unidad básica de programación es la función, de la misma manera que en los lenguajes orientados a objetos la unidad básica es la clase. En C lo fundamental es lo que ha de hacerse con los datos, en tanto que en la programación orientada a objetos (en C++, por ejemplo) lo principal son los datos. Los programas en C están compuestos de funciones. Todos deben tener al menos una: la función main.

{      /* Abre main */

main es un cuerpo de instrucciones. Cualquier cuerpo de instrucciones empieza con una llave izquierda.

int materias = 0;
int calificacion = 0;
int suma = 0;
float promedio = 0; 
/* Declarar antes de usar */

Las primeras cuatro líneas son declaraciones de variables. Estamos reservando espacios de memoria para almacenar números enteros (en el caso de materias, calificacion y suma) y un número de punto flotante (promedio). Las variables se pueden declarar en cualquier parte dentro de la función main, siempre y cuando ésto se haga antes de usarlas. A estas variables se les ha asignado un valor (0 en todos los casos). Es recomendable asignar valores a las variables cada vez que se declaran; aunque ésto no es obligatorio, sí es conveniente. Cada vez que se declara una variable, ésta obtiene un valor "basura". Hacer referencia a esa variable, suponiendo de manera errónea que se le ha asignado un valor válido, por ejemplo, mediante la función printf, produce un error no fatal (un error que no detiene la ejecución del programa, y por lo tanto hace que el usuario pueda suponer, también de manera errónea, que el programa hace su tarea correctamente).
El operador de asignación (=) tiene una asociatividad de derecha a izquierda, esto es, toma el valor a la derecha y lo asigna a la variable de la izquierda; es también un operador de muy baja precedencia, esto es, si en un programa en C usted observa una instrucción como esta: x = y + 1; entonces puede estar seguro que primero se realizará la suma y después la asignación: la precedencia del operador + es superior a la del operador =. Pronto veremos más sobre la precedencia y la asociatividad de los operadores en C.
¿Por qué declaramos a la constante promedio como tipo float? Los números float son números con parte decimal (números con punto flotante). Como queremos que la calificación final del alumno sea la más justa posible, tenemos que tomar el promedio como un número con decimales. Si nosotros declaramos promedio como tipo entero, entonces al hacer la división, suma/calificaciones, el resultado se truncará NO al entero inferior, sino al entero más cercano a 0.
La última línea es un comentario, que nos advierte que hay que declarar las variables antes de usarlas.

printf("\nEste programa recibe las calificaciones de un alumno ");
printf("y calcula e imprime el promedio.\n"); 
 

Un mensaje para el usuario. Si el usuario no tiene acceso al código, y no somos explícitos en cuanto a lo que queremos de él, entonces estará en problemas. Es conveniente indicar siempre que sea posible el propósito general del programa en un mensaje general.

printf("\nIntroduzca la calificacion de la primera materia: (negativo para terminar)\n"); 

Un mensaje pidiendo la primera calificación.

scanf("%d", &calificacion); 

y a continuación se recibe.

printf("\nCalificacion = %d", calificacion);  

Este printf es totalmente prescindible, sólo se imprime la calificación que el usuario acaba de introducir.

while ( 0 < calificacion ) 

while, en inglés, significa literalmente "mientras", un buen nombre para la instrucción. La condición entre paréntesis evalúa que el valor de la calificación sea mayor que 0. El cuerpo de while se ejecutará si la condición entre paréntesis se cumple y mientras ésta sea verdadera.

{     /* Abre while */ 

El cuerpo de instrucciones se limita por llaves. Si no hay llaves, while toma por instrucción la inmediata siguiente. También es posible no tener un cuerpo de instrucciones, lo cual se obtiene cuando al final de los paréntesis que contienen la condición aparece un punto y coma.

suma = suma + calificacion; 

Probablemente sea necesario un conocimiento mínimo de qué es y cómo funciona el modelo teórico de una computadora para entender bien esta instrucción. Ante todo no hay que confundirla con una ecuación algebraica. El operador de asignación =, como se ha dicho, es un operador de baja precedencia y con un asociatividad de derecha a izquierda. Primero se realiza la suma, se toma el valor guardado en la variable "calificacion" (el operador + también tiene una asociatividad de derecha a izquierda) y se suma con el valor almacenado en la variable "suma", esta cantidad, que la computadora guarda en una memoria temporal interna, es asignada luego a la variable "suma", borrando la cantidad almacenada previamente. Los nombres de variables no son más que eso, nombres para identificar un espacio de memoria en el cual se almacenan datos. Esos espacios de memoria con frecuencia cambian, durante la ejecución de un programa, el contenido que almacenan, aunque el espacio en sí sigue teniendo el mismo tamaño (tipo de datos) y nombre (nombre declarado de la variable).

materias = materias + 1;  

Esta expresión es sintácticamente igual a la precedente. Primero, 1 se suma al valor almacenado en la variable "materias" y luego ese resultado se almacena en la variable "materias", borrando el valor anterior.

printf("\nIntroduzca la calificacion de la siguiente materia: (negativo para terminar)\n");
scanf("%d", &calificacion);


 }     /* Cierra while */ 

En la mayoría de los lenguajes de programación "modernos", las llaves {} son utilizadas para delimitar cuerpos de instrucción. Lenguajes muy viejos, como Ada, Cobol o Fortran, no limitan cuerpos de instrucción de esta manera, lo cual, a mi gusto, los hace más difíciles de leer.
Esta llave indica el fin del cuerpo de instrucciones while.

if ( 0 != materias )

Este es un condicional if. La condición es: ¿el número de calificaciones es diferente de 0? La forma de escribir la condición es similar a if (materias != 0). ¿Por qué se escribe entonces de la forma en que aparece en el programa? Para evitar una asignación en el segundo caso si se olvida escribir el signo !.

promedio = (float)suma/materias;

Esta asignación es simple. Se realiza la división suma/materias y se le asigna el resultado a la variable "promedio". ¿Por qué aparece la sentencia (float)? Porque las variables "suma" y "materias" son las dos de tipo int. Cuando realizamos operaciones aritméticas con variables del mismo tipo de datos, el resultado conserva el tipo. Por ejemplo al dividir suma (una variable entera) entre materias (una variable también entera) el resultado no tiene más que ser un entero. Sin embargo, "suma" podría no ser múltiplo de "materias", o, en otras palabras, suma/materias podría ser un número con decimales. En ausencia de (float) esto truncaría el valor de la división NO al entero más pequeño, sino al más cercano a 0 (ésta convención es una norma que usan C y C++ derivada del lenguaje Fortran). A pesar de que el lado derecho de la expresión es un tipo int y el izquierdo es un float, esto no crea ningún conflicto. Es posible asignar un valor entero a un float, ya que el compilador de C realiza una transformación automática de tipos (la expresión de la derecha se convierte al tipo de la izquierda). Sin embargo, lo contrario no es cierto: no se puede asignar un valor float a un entero. En general es posible asignar un valor "pequeño" a un tipo "grande", pero no al revés. La razón por la cual aparece (float) antes de suma es porque con esa instrucción convertimos explícitamente suma a tipo float y dado que sólo se puede operar con tipos iguales, el compilador convierte "calificaciones" implícitamente a float. Así que ahora la división se realiza entre dos tipos float y por lo tanto el resultado es un float de orígen que incluye números decimales. Ése resultado se almacena en la variable promedio.

else
promedio = 0;

La razón de if-else en este caso es evitar una división entre 0. Si no se ha introducido ninguna calificación, ocurrirá un error no fatal. En programación, como en aritmética, no se debe dividir entre 0 y se debe evitar que esto ocurra.

printf("\nEl promedio de este estudiante es: %.3f \n", promedio);

La función printf imprime el promedio calculado. Lo único nuevo aquí es "%.3f". Para imprimir una variable float, basta con escribir "%f", tal como para imprimir un entero basta con "%d". Si sólo escribimos "%f", se imprimirá un número con 6 decimales por defecto. Esto puede ser demasiado para los fines de una calificación. Por esta razón se utiliza "%.3f", esto hace que los decimales que se impriman sean solamente 3. La siguiente tabla muestra que si quiere obtener una precisión de 4 decimales deberá escribir "%.4f", etc. Usted puede producir un número tan grande como cifras decimales quiera, pero deberá tener en cuenta que la precisión real del número depende del tamaño de la memoria en la que se almacena el tipo de datos float (vuelva a leer la entrada La Representación en complemento a dos), así que después de cierta número de cifras decimales,las siguientes serán 0.

___________________________________________________________
|         ENUNCIADO                        |      PRODUCE   |
|__________________________________________|________________|
|printf("%f". VariableFlotante);           |      1.000000  | 
|printf("%.1f", VariableFlotante);         |      1.0       |
|printf("%.2f", VariableFlotante);         |      1.00      |
|printf("%.3f", VariableFlotante);         |      1.000     | 
|printf("%.4f", VariableFlotante);         |      1.0000    |
|printf("%.4f", VariableFlotante);         |      1.00000   |
|__________________________________________|________________|


}      /* Cierra main */

Esta llave cierra el cuerpo de main, lo cual indica el fin del programa.
_____________________________________________________________________________________________
CICLO WHILE CONTROLADO POR CONTADOR
_____________________________________________________________________________________________
Vamos a considerar una pequeña variante del programa anterior. Supongamos que sabemos cuántas materias ha cursado nuestro alumno y, por lo tanto, cuántas calificaciones vamos a recibir. Sean por caso 10. En ese caso el programa es modificado sólo un poco, para quedar de la siguiente manera:

/*++++++++++++++++++++++++++++++++++++++++++
 +                                          +
 + Este programa recibe calificaciones de   +
 + 1 alumnos e imprime su promedio          +
 +                                          +
 +++++++++++++++++++++++++++++++++++++++++++*/

 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 *                                                                   +
 +                           ALGORITMO:                              +
 +                                                                   +
 + Establece el numero de calificaciones en 0                        +
 +                                                                   + 
 + Mientras el numero de calificaciones sea menor a 10               +
 + {                                                                 + 
 + Pedir al usuario la calificacion de la siguiente                  +
 + Recibe la calificacion                                            +
 + Suma la calificacion actual a la suma acumulada de calificaciones +
 + Incrementa el numero de calificaciones en 1                       +
 + }                                                                 +
 +                                                                   +
 + El promedio del alumno es la suma acumulada de calificaciones     +
 + dividida entre el numero de calificaciones                        + 
 +                                                                   +
 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

 #include <stdio.h>
 
 int main()

 {      /* Abre main */
 int ContadorMaterias = 0;
 int calificacion = 0;
 int suma = 0;
 float promedio = 0; 
 /* Declarar antes de usar */
 
 printf("\nEste programa recibe las calificaciones de 10 materias de un alumno ");
 printf("\ny calcula e imprime el promedio.\n");
 
 while ( 10 > ContadorMaterias )
 {     /* Abre while */
 ContadorMaterias = ContadorMaterias + 1;
 printf("\nIntroduzca la calificacion de la materia %d: \n", ContadorMaterias);
 scanf("%d", &calificacion);

 suma = suma + calificacion;
 
 }     /* Cierra while */ 

 if ( 0 != ContadorMaterias )
 promedio = (float)suma/ContadorMaterias;
 else
 promedio = 0;

 printf("\nEl promedio de este estudiante es: %.3f \n", promedio);
 
 }      /* Cierra main */

Como ya se ha comentado arriba las instrucciones, vamos a concentrarnos en la diferencia. La condición en while es un poco distinta:

while ( 10 > ContadorMaterias )

La variable ContadorMaterias realiza la misma tarea que en el programa de arriba realizó la variable materias. Como ahora sabemos de antemano cuántas veces se tienen que realizar el cuerpo de instrucciones (recibir las calificaciones, aumentar el número de materias, etc) ésa condición se escribe entre paréntesis. Mientras el contador de materias sea menor que 10, se incrementará en 1 la variable ContadorMaterias y se pedirá la siguiente calificación, etc. Esta forma de controlar el ciclo while se llama por contador. El ciclo se realiza tantas veces como lo indique el contador. Es importante ver que cuando la variable ContadorMaterias se definió, se le asignó el valor 0. Dentro del cuerpo de while, y antes de hacer cualquier otra cosa, se incrementa su número en 1. Por esta razón en la condición se pide que 10 > ContadorMaterias, no >=. Si la variable se hubiera iniciado en 1, entonces la condición sí sería >= y el incremento se daría al final del cuerpo de instrucciones. Es muy común cometer errores por defecto o exceso en 1 cuando se controla un ciclo while por contador.
_____________________________________________________________________________________________
Lo que aprendió:
El uso de la instrucción while
Cómo controlar un while con centinela
Cómo controlar un while con contador
La precedencia del operador =
La precedencia del operador +
Imprimir números flotantes con precisión.
_____________________________________________________________________________________________
Esta entrada forma parte del Curso De C Con Programas Explicados Línea Por Línea
Índice
Entrada Anterior
Entrada Siguiente

6 comentarios:

  1. ummmmmmmmmmmmm poko knfuso ...pero genial...

    ResponderEliminar
  2. Buenaza tu explicación, lo entendí completamente. Gracias, muy amable.

    ResponderEliminar
  3. ¡Gracias por los comentarios!

    ResponderEliminar
  4. oye amigo tengo un programa que me pide introducir n numeros y me pide contar cuantos son positivos y cuantos son regativos me podrias ayudar porfavor

    ResponderEliminar
    Respuestas
    1. Hola. Me parece que es muy fácil. Tienes que llevar un contador para cada caso

      int pares;
      int impares;

      if( 0 == x%2)
      ++pares;
      else
      ++impares;

      Eliminar
    2. no puedes decir que 0==x%2 , estas errando, lo correcto es x%2==0, y también debes declarar la variable "x", ya se que es antiguo el post.

      Eliminar

Related Posts Plugin for WordPress, Blogger...