Está en la página 1de 13

P RÁCTICAS DE F UNDAMENTOS DE I NFORMÁTICA

DIPLOMATURA EN ESTADÍSTICA
CURSO 2009 – 2010

MARTES 17 Y JUEVES 19 DE NOVIEMBRE DE 2009


SESIÓN

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.

BUCLES CONTROLADOS POR CONTADOR: FOR


En los bucles controlados por contador, antes
de comenzar el bucle siempre se conoce
cuántas iteraciones se van a realizar. En unos
INICIALIZACIÓN

casos este número de iteraciones se conoce en 1


tiempo de compilación o de diseño del
programa (por ejemplo, si queremos crear un Evaluar expresionInicial
Evaluar expresionFinal
programa que pida al usuario exactamente diez contador := expresionInicial
números y calcule la suma de todos ellos). En
otros casos, el número de iteraciones no se
conoce hasta tiempo de ejecución (por
ejemplo, si queremos que el usuario introduzca
primero cuántos números quiere sumar, que
puede ser cualquiera, y luego ya iterar todas TRUE ¿contador >
expresionFinal?
esas veces para pedir al usuario que introduzca
EJECUCIÓN

2b
cada uno de los números a sumar). 2a FALSE

Como podemos ver en la imagen de la derecha, BLOQUE DE INSTRUCCIONES


(no pueden modificar contador)
la estructura de los bucles controlados por
contador es muy sencilla. Cada bucle de este
tipo tiene asociada una variable contador, a las contador := contador + incremento
que se suelen llamar i, j, k, y así sucesivamente.
En una primera fase de INICIALIZACIÓN se
determina cuáles van a ser el valor inicial y el
valor final del contador (para lo cual hay que
evaluar dos expresiones) y se asigna al contador ese valor inicial. A continuación, durante la
EJECUCIÓN del bucle, en cada iteración se comprueba primero si el contador es mayor que el
Eduardo E isman – eisman@decsai.ugr.es – http://decsai.ug r.es/~eisman 1
Depart amento de Ciencias de la Computación e Inteligencia Art if icial – ETSIIT – Un iversid ad de Granada
valor final. Si el contador no ha llegado todavía al valor final (caso 2a ), entonces se ejecuta el
bloque de instrucciones del cuerpo del bucle, y a continuación se incrementa (o decrementa) el
valor de la variable contador, tras lo cual se vuelve a comparar con el valor final. Cuando el
contador es mayor que el valor final (caso 2b ), se termina la ejecución del bucle y se siguen
ejecutando las instrucciones que vienen debajo, fuera del bucle.

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.

2 Práct icas de Fundamentos de Informátic a – Curso 2009 – 2010


Diplomatu ra en Estadíst ica – Universidad de Granada
En este caso, hemos indicado que desde i igual a 1, hasta 10, con incrementos positivos de 1 en 1
(to), se muestre por pantalla el valor de dicha variable i utilizando la instrucción writeln. Observa
que en este caso hemos incluido una sola sentencia en el cuerpo del bucle. Si quisiésemos incluir
más de una, tendríamos que meterlas dentro de un bloque begin ... end;. Copia el programa y
modifícalo para que los números aparezcan en orden descendente, es decir, del 10 al 1 en lugar de
del 1 al 10. Cuando hayas terminado, modifica, dentro del cuerpo del bucle, la variable contador i.
Por ejemplo, intenta restarle un 1 al contador para que solamente se muestren por pantalla los
números pares. Al compilar, te darás cuenta de que Pascal no permite modificar el valor de la
variable contador dentro del cuerpo del bucle for (otros lenguajes de programación como C o Java
sí que permiten realizar un incremento distinto de +1 ó –1). Entonces, ¿qué otra forma se te ocurre
para mostrar solamente los números pares utilizando las estructuras que hemos visto hasta hoy?
Intenta hacerlo incluyendo un if dentro del cuerpo del bucle for.

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

Eduardo E isman – eisman@decsai.ugr.es – http://decsai.ug r.es/~eisman 3


Depart amento de Ciencias de la Computación e Inteligencia Art if icial – ETSIIT – Un iversid ad de Granada
Si te fijas, en realidad estamos repitiendo tres veces el trozo de código que pide un número, lo lee y
lo acumula en la suma total. Por lo tanto, podríamos haber utilizado un bucle for y habernos
ahorrado el escribir tanto. Además, si detectamos un fallo en cualquiera de las instrucciones, es más
fácil tener que arreglar una sola instrucción dentro del for, que si tenemos la misma instrucción
repetida un montón de veces

4 Práct icas de Fundamentos de Informátic a – Curso 2009 – 2010


Diplomatu ra en Estadíst ica – Universidad de Granada
Observa cómo hemos tenido que crear un bloque (con begin y end) dentro del bucle for ya que
íbamos a escribir más de una sentencia. Si no lo hubiésemos hecho, solamente el write habría
quedado dentro del bucle, y tanto el readln como la asignación de la suma habrían quedado fuera.
El problema que tiene ahora esta solución es que el número de iteraciones se ha fijado en tiempo
de compilación, es decir, que siempre se calcula la media de tres números, por lo que el programa
no nos vale si queremos calcular la media de diez números (tendríamos que cambiar en el código el
3 por un 10 y volver a compilar el programa). Intenta modificar el ejemplo anterior de forma que el
programa sirva para calcular la media de todos los números que queramos. Por lo tanto, el número
de iteraciones no será un valor constante sino que se conocerá en tiempo de ejecución. Tendrás que
pedirle primero al usuario que introduzca de cuántos valores quiere calcular la media, y luego
utilizar dicho valor para establecer el número de iteraciones que debe realizar el bucle.

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

BUCLES CONTROLADOS POR CONDICIÓN: WHILE, REPEAT


En los bucles controlados por condición no es necesario conocer cuántas veces ha de iterar el
bucle. En este caso, el conjunto de sentencias del cuerpo se ejecuta mientras (o hasta que,
dependiendo del tipo de bucle) la condición que controla el bucle sea verdadera. Exiten dos tipos
de bucles controlados por condición. Los bucles while ejecutan el cuerpo del bucle mientras que se
cumple una expresión lógica, también llamada condición o centinela. Los bucles repeat ejecutan el
cuerpo del bucle hasta que se cumple una expresión lógica. En los bucles while, la condición se

Eduardo E isman – eisman@decsai.ugr.es – http://decsai.ug r.es/~eisman 5


Depart amento de Ciencias de la Computación e Inteligencia Art if icial – ETSIIT – Un iversid ad de Granada
evalúa antes de ejecutar el cuerpo del bucle (pre-test), mientras que en los bucles repeat primero se
ejecuta el cuerpo del bucle y luego se comprueba la condición (post-test). Esto implica que en los
bucles repeat, el conjunto de instrucciones siempre se ejecuta al menos una vez, mientras que en
los bucles while las instrucciones podrían incluso no llegar a ejecutarse nunca si la condición de
entrada al bucle es falsa la primera vez.

La siguiente imagen refleja la filosofía de ambos tipos de bucles

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 volver a iterar cierta, entonces saltamos al


2b _Si la condicion no es cierta, comienzo del bucle para volver a
acabamos el bucle y continuamos iterar
el flujo normal de ejecución del 2b _Si la condicion es cierta,
programa acabamos el bucle y continuamos
el flujo normal de ejecución del
programa

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

6 Práct icas de Fundamentos de Informátic a – Curso 2009 – 2010


Diplomatu ra en Estadíst ica – Universidad de Granada
Tal y como podemos apreciar en el código y en el
esquema de la derecha, lo que hace el programa es
1
partir del número que se lee n, y 2 ir
1 i := n
disminuyendo hasta llegar al 0 (la condición de
ejecución del cuerpo del bucle es que el valor de la
variable i sea mayor que 0). 2a Para cada una de
esas iteraciones, 3 se comprueba si el número
CONDICIÓN
DEL BUCLE

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

Eduardo E isman – eisman@decsai.ugr.es – http://decsai.ug r.es/~eisman 7


Depart amento de Ciencias de la Computación e Inteligencia Art if icial – ETSIIT – Un iversid ad de Granada
primera vez, como no la estamos modificando dentro del bucle, este no acabará nunca, y el bloque
de sentencias se ejecutará indefinidamente, impidiendo que se ejecuten las sentencias que vengan
después del bucle. Es lo que se conoce como bucle infinito. Por lo tanto, para evitar iterar
indefinidamente, dentro del bucle siempre debemos modificar alguna de las variables que
intervienen en la condicion, de manera que en algún momento esta sea false y finalice el bucle.

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

8 Práct icas de Fundamentos de Informátic a – Curso 2009 – 2010


Diplomatu ra en Estadíst ica – Universidad de Granada
Un ejemplo de ejecución de este programa sería el siguiente

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

Eduardo E isman – eisman@decsai.ugr.es – http://decsai.ug r.es/~eisman 9


Depart amento de Ciencias de la Computación e Inteligencia Art if icial – ETSIIT – Un iversid ad de Granada
La salida del programa por pantalla sería la que se muestra a continuación

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

ASEGURANDO UNA BUENA ENTRADA DE DATOS


Antes de que viésemos los bucles, siempre que íbamos a leer un dato por teclado confiábamos
ciegamente en que el usuario iba a ser bueno e iba a introducir uno de los datos que nosotros
esperábamos. Por ejemplo, si era una nota, debía ser un número entre 0 y 10, si era un número
entero no podía ser una carácter, etc. Sin embargo, tenemos que pensar siempre lo contrario, nunca
podemos confiar en que una entrada de datos se vaya a realizar correctamente, ya que el usuario
puede despistarse y meter un dato incorrecto, e incluso hay usuarios con malas intenciones que van
a intentar colgar nuestro programa en cuanto les sea posible.

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)

10 Práct icas de Fundamentos de Informátic a – Curso 2009 – 2010


Diplomatu ra en Estadíst ica – Universidad de Granada
El código de error indica el tipo de error que se ha producido. ¿Cómo podemos controlar este tipo
de errores para que nuestro programa no falle? Existen dos opciones para evitar que el programa
lance este mensaje de error. La primera alternativa es desactivar temporalmente que se lancen los
mensajes de error. Así, leemos el dato, y luego miramos si era del tipo que nos interesaba. Si no lo
era, podemos volver a pedirlo, tal y como muestra la siguiente imagen

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

Eduardo E isman – eisman@decsai.ugr.es – http://decsai.ug r.es/~eisman 11


Depart amento de Ciencias de la Computación e Inteligencia Art if icial – ETSIIT – Un iversid ad de Granada
Pero como vemos, esta segunda alternativa implica tener que cambiar una opción en el compilador
de Pascal, ya que en caso contrario no se reconoce el identificador try. Para solucionar este
problema, nos vamos a la opción ‘Compiler...’ del menú ‘Options’

Una vez allí elegimos el compiler mode ‘Object Pascal extension on’

12 Práct icas de Fundamentos de Informátic a – Curso 2009 – 2010


Diplomatu ra en Estadíst ica – Universidad de Granada
Con esto ya podremos compilar y ejecutar el programa.

EJERCICIOS PARA PRACTICAR


Ejercicio 01 Realiza un programa que calcule la suma de todos los números enteros entre 1 y 10.
Ejercicio 02 Construye un programa que calcule, de forma independiente, la suma de los números
pares e impares comprendidos entre 1 y 200.
Ejercicio 03. Crea un programa que lea números enteros hasta que se introduzca un número par.
Ejercicio 04 Crea un programa que calcule y muestre por pantalla las potencias de 2 entre 0 y 10.
Ejercicio 05 Calcula la suma de los cuadrados de los 50 primeros números naturales.
Ejercicio 06 Realiza un programa que muestre por pantalla los múltiplos de 4 comprendidos entre 4
y n, donde n es un número introducido por teclado.
Ejercicio 07 Elabora un programa que lea una serie de números enteros positivos distintos de 0 y
muestre por pantalla el máximo. El último número de la serie debe ser el –1.
Ejercicio 08 Construye tres programas (usando los bucles for, while y repeat) que permitan realizar
la suma de n números introducidos por teclado.
Ejercicio 09 Escribe un programa que lea 5 grupos de 4 valores cada uno y que, para cada grupo,
calcule la media y la muestre en pantalla. (Nota: utiliza bucles anidados)
Ejercicio 10 Crea un programa que lea una lista de números positivos que finaliza en 0 y muestre
por pantalla el valor mínimo de dicha lista y en qué posición se encontraba.
Ejercicio 11 Dada una lista de valores numéricos positivos, finalizada en 0, realiza un programa
que indique si la lista está ordenada en forma ascendente.
Ejercicio 12 Escribe un programa que permita calcular xn, donde x puede ser cualquier real distinto
de 0 y n puede ser cualquier número entero (positivo, negatio o nulo).
Ejercicio 13 Construye un programa que determine si un número leído por teclado es primo.
Ejercicio 14 Realiza un programa que encuentre los n primeros números primos.
Ejercicio 15 Escribe un programa que muestre la representación en binario de un número decimal.

Este documento está protegido bajo una licencia Creative Commons.


No se permite un uso comercial de la obra ni la generación de obras derivadas.

Eduardo E isman – eisman@decsai.ugr.es – http://decsai.ug r.es/~eisman 13


Depart amento de Ciencias de la Computación e Inteligencia Art if icial – ETSIIT – Un iversid ad de Granada

También podría gustarte