Documentos de Académico
Documentos de Profesional
Documentos de Cultura
DIPLOMATURA EN ESTADÍSTICA
CURSO 2009 – 2010
04 FOR Y WHILE
Las estructuras de repetición o iterativas (también llamadas bucles, ciclos o lazos) permiten repetir
la ejecución de un conjunto de sentencias un número determinado (o indeterminado) de veces. La
idea es escribir una única vez aquella parte que se repite (la cual se llama ámbito o cuerpo del
bucle) e indicar cuántas veces se ha de repetir. En cada repetición, las variables que intervienen
cambian su valor siguiendo un tipo de secuencia que se puede obtener fácilmente. El número de
veces que se ejecuta el cuerpo del bucle depende del tipo de bucle en sí (hay dos tipos diferentes).
Existen bucles controlados por contador (bucles for) en los que se fija de antemano cuántas veces
se va a ejecutar el cuerpo del bucle. También hay bucles controlados por condición (bucles while y
repeat), en los que las instrucciones del cuerpo se ejecutan mientras o hasta que se satisface una
determinada condición.
2b
cada uno de los números a sumar). 2a FALSE
En Pascal, este tipo de bucles se llaman bucles for, y se escriben de la siguiente manera (el código
de abajo no compila todavía, sólo es para que veamos la estructura general de los bucles for)
Es decir, primero se evalúa la expresión inicial y la expresión final que pongamos. A continuación,
se le asigna a la variable contador el resultado de evaluar esa expresión inicial. Después, mientras la
variable contador sea menor o igual que el valor final, se ejecutará el bloque de instrucciones del
cuerpo del bucle. Observa que el incremento o decremento de la variable contador se hace
automáticamente al final de cada iteración (después de haber ejecutado el bloque de
instrucciones). Si ponemos for ... to, la variable contador se incrementa en una unidad al final de
cada iteración. Si ponemos for ... downto, la variable contador se decrementa en una unidad al
final de cada iteración.
Veamos un ejemplo muy sencillo para aclarar las ideas. Vamos a mostrar por pantalla los números
del uno al diez. Podríamos hacerlo utilizando diez instrucciones writeln, o mejor aún, utilizando una
sola instrucción writeln pero incluyéndola dentro de un bucle for que se ejecuta diez veces.
Realicemos un pequeño inciso sobre el cálculo del valor final del contador del bucle. Supongamos
que tenemos el siguiente programa
En él hemos incluido una nueva variable num de tipo entero. Esta variable se inicializa al valor 1 y
se utiliza en la expresión final del bucle. Asimismo, dentro del bucle se modifica el valor de esta
nueva variable (se permite, ya que no es la variable contador del bucle) para asignarle el valor 2.
¿Cuántas iteraciones crees que se realizarán? ¿10? ¿20? Compruébalo, pero recuerda que el valor
final del contador del bucle se calcula evaluando la expresión final una única vez en la fase de
inicialización del bucle y no en cada iteración. Por lo tanto, la modificación de la variable num
dentro del bucle no afecta al número de iteraciones que realiza el bucle.
Sigamos con otro ejemplo. Queremos crear un programa que calcule la media de tres números
reales que se leen por teclado. Con los conocimientos que tenemos hasta ahora podríamos dar la
siguiente solución
Finalmente indicar que, al igual que cuando utilizábamos las estructuras condicionales if y case
vimos que estas se podían anidar (incluir unas dentro de otras), los bucles for también se pueden
anidar. Como veremos en futuras sesiones, esto nos será muy útil cuando trabajemos con matrices,
ya que tendremos que leer, para cada una de las filas de la matriz (primer bucle for más exterior),
cada uno de los valores de las columnas de esa fila (segundo bucle for interior al otro).
WHILE REPEAT
1
REPETIR MIENTRAS
REPETIR HASTA
FALSE BLOQUE DE INSTRUCCIONES
¿condicion? 1 (modifica la variable que
2b interviene en la condicion)
2a TRUE
FALSE
BLOQUE DE INSTRUCCIONES ¿condicion?
(modifica la variable que
interviene en la condicion) 2a
2b TRUE
1 1
Se evalúa la condicion _Se ejecuta el bloque de
2a Si la condicion es cierta, se ejecuta instrucciones sin hacer ninguna
el bloque de instrucciones y comprobación previa
saltamos al comienzo del bucle 2a Se evalúa la condicion, y si no es
Para ver cómo podríamos escribir este tipo de bucles en Pascal, vamos a analizar un par de
ejemplos. El siguiente programa calcula los divisores de un número cualquiera
2
asociado a la iteración actual i divide al número que
¿i > 0? FALSE
hemos leído por teclado (si el módulo vale 0). 3a
En ese caso, se muestra el valor de i por pantalla, ya 2b
que es un divisor. Es muy importante que te fijes TRUE 2a
además en que en los bucles while, la sentencia de
incremento (o decremento) del contador hay que 3
ponerla explícitamente. Además, al contrario de lo FALSE
¿(n mod i) = 0?
que ocurría en los bucles for en los que el
incremento sólo podía ser +1 o –1 (según 3b
DEL BUCLE
CUERPO
TRUE 3a
utilizásemos to o downto), en los bucles while se
puede poner el incremento que queramos. Un error write(i)
muy común es que se nos olvide incluir dentro del
bucle la sentencia que modifica la condición. ¿Qué
ocurre si eliminamos la sentencia i := i -1; del
ejemplo anterior? Compruébalo. Te darás cuenta de i := i - 1
que el programa se bloquea y no responde. Para
cerrarlo, pulsa ‘Ctrl + C’. ¿Qué ha pasado? El
problema es que si la condición del bucle es true la
El ejercicio anterior se podía haber resuelto también utilizando un bucle for, desde i igual a n hasta
1. Intenta resolverlo tú así. En general, cualquier bucle for puede reescribirse como un bucle
while. Sin embargo, no todos los bucles while pueden reescribirse como bucles for. Por lo tanto, el
concepto de bucle while es algo mucho más amplio.
Para practicar un poco más intenta resolver, utilizando bucles while, el ejercicio que vimos
anteriormente que listaba los números pares comprendidos entre el 1 y el 10. A continuación,
modifica el programa para que se pida por teclado ese límite inferior y superior, de forma que se
listen todos los números pares entre ellos.
Otra de las aplicaciones de los bucles while es la lectura de datos utilizando lo que se conoce como
control por centinela. La idea es leer datos indefinidamente en un bucle hasta que se introduce un
dato en particular, el cual provoca la salida del bucle. Este dato de parada se conoce como
centinela, y debe ser diferente al de cualquier dato de entrada válido. Por ejemplo, si tenemos un
programa que calcula la nota media de los alumnos de una asignatura, podemos ir pidiendo notas
por teclado hasta que se introduzca una nota negativa (que no es una nota válida), lo cual indicaría
que ya no queremos introducir más notas
Podemos ver cómo el programa pide que introduzcamos notas hasta que introducimos una que no es
válida (–1), que actúa como centinela y detiene la ejecución del bucle.
Como ejemplo de uso del bucle repeat, podemos comentar la creación de menús de opciones. Por
ejemplo, supongamos que queremos hacer un único programa que tenga muchas utilidades
diferentes, es decir, que pueda calcular por ejemplo los divisores de un número, decir si es primo o
no, etc. Todo desde un mismo programa. Para seleccionar cuál es la utilidad que queremos, el
usuario deberá elegir una opción de un menú que mostraremos por pantalla
Y si elegimos la opción ‘2’ por ejemplo, se realizaría el cálculo asociado, tras lo cual se nos
permitiría volver de nuevo al menú de opciones.
Al igual que anteriormente dijimos que cualquier bucle for se podía transformar en un bucle while,
los bucles repeat también pueden convertirse en bucles while. Esto se puede conseguir de dos
formas diferentes. La primera consiste en repetir el cuerpo del bucle justo antes del bucle en sí
mismo, de forma que todas esas sentencias se ejecutan al menos la primera vez. La segunda consiste
en darle un valor a la variable que interviene en la condición del bucle para que esta se cumpla
siempre la primera vez (y ya dentro del bucle la modificamos, pero nos aseguramos de que
entramos al menos una vez).
En esta sesión ya hemos visto unos primeros consejos sobre cómo podemos controlar que el usuario
meta un dato válido. Para ello, metemos la lectura del dato en un bucle repeat o while, y forzamos a
que se vuelva a pedir el dato mientras no sea uno que nos venga bien (que no sea una opción del
menú, o que la nota no esté entre 0 y 10, etc.). Sin embargo, estos consejos se basan en la
suposición de que el usuario va a introducir un dato del mismo tipo al que esperamos, por lo que el
problema que estamos controlando es que el valor esté fuera de un rango o conjunto de opciones.
Pero, ¿qué pasa si esperamos un entero y el usuario introduce un carácter? Se detiene la ejecución
del programa y se muestra el siguiente mensaje de error (seguro que os ha pasado alguna vez)
Al incluir {$I-} (o de forma equivalente {$IOCHECKS OFF}) conseguimos que los mensajes de
error que se produzcan en la entrada / salida se controlen a través de la variable IOResult. A
continuación ya podemos realizar la lectura del dato con total tranquilidad. Una vez que terminemos
de leer el dato de entrada, volvemos a activar el control de errores utilizando excepciones mediante
{$I+} (o {$IOCHECKS ON}). Para saber si hemos leído el dato correctamente, sólo tenemos que
consultar el valor de la variable IOResult. Si es distinto de cero, es que se ha producido algún error
y hay que volver a leer el dato. Si no, la lectura se ha realizado correctamente y podemos seguir con
nuestro programa.
La segunda opción es mantener los mensajes de error activos, y lo que hacemos es capturar el
error. Para ello se utilizan los bloques try ... except, y try ... finally (no entraremos en detalle en el
manejo de excepciones, sólo interesa que tengáis una idea general al respecto). Cuando se produce
un error de entrada / salida, se lanza la excepción (el error) EInOutError. Pues bien, lo único que
tenemos que hacer es encerrar las instrucciones que puedan dar ese tipo de error dentro de un try ...
except
Una vez allí elegimos el compiler mode ‘Object Pascal extension on’