Está en la página 1de 176

Programacin estructurada en Pascal

ENTREGA NMERO 1

MANUAL DE PROGRAMACIN BSICA

LENGUAJE DE PROGRAMACIN PASCAL

Vladimir Rodrguez

Programacin estructurada en Pascal

Vladimir Rodrguez

Programacin estructurada en Pascal

PRIMERA PARTE

Conceptos bsicos de programacin

Vladimir Rodrguez

Programacin estructurada en Pascal Introduccin:


Existe un gran nmero de personas que escriben a foros y blogs en la WEB en la bsqueda de distintos manuales o tutoriales que enseen a programar desde cero, o sea, que alguien que no sepa nada en absoluto sobre la programacin sea capas de aprender con solo leer. En efecto, eso es posible y es a lo que apunta este tutorial. Deben saber que la base para ser un buen programador es la prctica. Debern trabajar mucho y realizar muchos programas, por ms tontos e inservibles que parezcan, cada vez que aprendan un concepto nuevo. Encontrarn varios ejercicios en este tutorial que les ayudarn a solidificar lo que hayan aprendido hasta el momento. Quiero reafirmar la importancia de la prctica. Los lenguajes de programacin tienen reglas muy estructuradas sobre sintaxis y semntica as como tambin muchas palabras que uno debe ir aprendiendo y comprendiendo en profundidad. Tambin est el hecho de que uno debe desarrollar una forma de pensar y analizar los problemas demasiado lgica para lograr resolverlos creando programas de computadora. Aadir tambin que el gran conocimiento de matemtica facilitar mucho el desarrollo de software, pero sin embargo, si no se entienden demasiado con esta materia podrn aprender a programar, pero nunca olviden que la matemtica y la programacin estn profundamente ligadas. Una vez hayan ledo completamente este tutorial sern capaces de crear aplicaciones bsicas en el lenguaje Pascal, aunque estas podrn tener una gran complejidad. El objetivo de este texto no es que ustedes salgan programando software para vender ni nada por el estilo, es que aprendan a programar de la nada, es introducirlos al mundo de la programacin estructurada. Teniendo estos conocimientos en mente, ustedes sern capaces de aprender luego un lenguaje mucho ms moderno y complejo con mayor facilidad que si lo intentaran ahora, sin saber nada. Espero que les sea de mucha utilidad. Ante cualquier duda o aporte que tengan pueden escribirme a mi casilla de correo: mstrvladi@hotmail.com y les responder en breve. Desde ya muchas gracias por leer este tutorial.

Vladimir Rodrguez

Programacin estructurada en Pascal Nociones sobre Lenguaje de Programacin:


Supongo que cualquiera que se aventure a leer este manual es porque sabe lo que es usar una computadora y por ende, lo que es un programa de computadora, tambin conocido como aplicacin. Sin embargo estoy seguro de que a la mayora de las personas que saben lo que es un programa, si se les pidiera que le explicaran a alguien que jams ha visto una computadora, sin tener una enfrente, lo que es un programa no sabran como hacerlo. En realidad es muy sencillo de definir: Un programa es un conjunto de instrucciones bien detalladas que la computadora seguir al pie de la letra, nada ms. Un programador es quien escribe ese conjunto de instrucciones que sern interpretadas y seguidas por un procesador. Dicho as suena muy fcil. Uno escribe instrucciones que sern seguidas al pie de la letra por la computadora. Sin embargo este es el gran problema que hace que uno como programador tenga que romperse la cabeza pensando en como hacer que una computadora realice tal o cual accin y como tomar en cuenta todas las variantes que puede haber acerca de una misma situacin. Ahora bien, si uno como programador ha de escribir instrucciones, cmo lo hace? Es aqu donde entran en juego los lenguajes de programacin. Existen de dos tipos: Lenguajes de bajo nivel y Lenguajes de alto nivel. Los primeros se escriben en el vejo y querido cdigo binario el cual est constituido nicamente por 0 y 1 y es lo nico que un procesador (CPU) puede entender e interpretar. Tambin se conocen como lenguaje de mquina. Creo que todo el mundo est de acuerdo en que programar as es una tortura, es inhumano y sumamente tedioso y aburrido. Y pensar que en principio todo se haca as y muchas cosas an se hacen as. Gracias a la necesidad de poder crear aplicaciones de computadora de una forma ms fcil y entendible es que nacen los Lenguajes de Alto Nivel, que se parecen ms a los hablados por los seres humanos y por tanto son mucho ms comprensibles para nosotros. Sin embargo, como dije antes, una CPU solo entiende el lenguaje de mquina y por ende no uno de alto nivel. Aqu entra en juego un programa muy especial: el compilador. Un compilador es una aplicacin que se encarga de traducir ese cdigo de alto nivel parecido a un lenguaje humano a lenguaje de mquina para que pueda ser interpretado por una Unidad Central de Proceso (CPU). Y entonces como se programa un compilador? Como ven, a veces hay que seguir luchando con el cdigo binario. Lenguajes de alto nivel muy nombrados son: C, C++, C-sharp, Pascal, PHP, Java, HTML, Borland, Ruby, entre muchsimos otros ms. Dado que lo escrito en el lenguaje de alto nivel (cdigo fuente del programa) ser luego traducido por un compilador a 0 y 1, debe hacerse respetando una sintaxis y una semntica bien establecidas, sin excepciones. Nosotros especficamente en este manual aprenderemos las nociones bsicas de la programacin estructurada, cmo se estudia un problema dado y se comienza a crear el programa que lo resuelve, entre muchas otras cosas. Todo lo haremos con el lenguaje Pascal, que hoy en da solo es usado con fines acadmicos de aprendizaje, y debo decir que realmente funciona para ese fin.

Vladimir Rodrguez

Programacin estructurada en Pascal Instalando el ambiente de desarrollo Free-Pascal:


Para trabajar con Pascal utilizaremos el compilador Free-Pascal 2.2.2. Este programa debe ser descargado desde este enlace o desde la pgina oficial de Free Pascal: http://sourceforge.net/projects/freepascal/files/Win32/2.2.2/fpc-2.2.2.i386-win32.exe/download. Una vez descargado el instalador ejecutar el mismo y seguir los siguientes pasos: Nota: En las imgenes se observa la versin 2.0.2 y no la 2.2.2, sin embargo los pasos de instalacin son los mismos.

Presionar en Next.

Seleccionar un directorio de instalacin. Es recomendable aceptar el directorio que aparece por defecto (C:\FPC\2.x.x). Apretar el botn Next.

En la siguiente ventana, se seleccionan los componentes del compilador que van a ser instalados. Se recomienda seleccionar Full Instalation. En caso de que dispongan de poco espacio en su disco duro, pueden seleccionar Minimal Instalation

Apretar el botn Next

Vladimir Rodrguez

Programacin estructurada en Pascal

Next otra vez.

Asociar todos los tipos de archivos que ofrece, sobre todo los que terminan con la extensin .pas y luego apretar el botn Next.

Presionar en Install y esperar a que termine de instalar todos los archivos. Esto a veces puede tardar bastante a pesar de que el copilador pesa muy poco.

Apretar el botn Next y luego en Finish.

Si llegaron hasta aqu sin errores, el compilador qued instalado.

Vladimir Rodrguez

Programacin estructurada en Pascal Verificando instalacin


Ahora debemos verificar si el compilador qued correctamente instalado. Lo que haremos es ejecutar el compilador desde la lnea de comandos de la siguiente manera: El primer paso es reiniciar la computadora para que todas las modificaciones realizadas por el programa instalador tengan efecto. (Es posible que alcance con salir de la sesin y volver a entrar) Acceder al tem del men inicio; Inicio Ejecutar

Escribir cmd sin comillas y apretar la tecla ENTER.

En la consola escribir fpc y apretar la tecla ENTER, como en la figura:

Si todo est bien debera salir un mensaje similar al siguiente:

Para terminar presione enter varias veces hasta que termine de desplegar.

Vladimir Rodrguez

Programacin estructurada en Pascal


Si en lugar del mensaje anterior, aparece un mensaje que indica que el comando fpc no es vlido, significa que algo anduvo mal en la instalacin. Pueden probar a reiniciar la computadora y volver a realizar este paso de verificacin. Si siguen teniendo problemas, les recomiendo desinstalar el compilador y volver a comenzar de nuevo la instalacin. Si probaron reinstalar y sigue sin funcionar este paso de verificacin, ser necesario realizar alguna configuracin adicional, como les explico a continuacin: En primer termino, verifiquen la existencia de la carpeta C:\FPC\2.2.2\BIN\I386_WIN32. Pueden hacerlo utilizando el explorador de Windows, accediendo por Mi PC, luego Disco X: (donde X es la unidad de disco duro) y as sucesivamente. Tambin pueden verificarlo por el siguiente comando en la consola DOS: dir C:\FPC\2.2.2\BIN\I386_WIN32 Si esa carpeta no existe, estamos en problemas. La instalacin no copi los archivos necesarios, quizs no tengan los permisos requeridos para la instalacin. Intenten volver a instalar. Si la carpeta existe, verifiquen que en la misma hay un archivo de nombre fpc.exe. Si este archivo existe, solamente hay que decirle al sistema donde puede encontrarlo (se supone que la instalacin lo hace automticamente, pero por alguna razn no funcion). Procedan de la siguiente manera:

1. 2. 3. 4.
o o

Accedan Mi Pc Panel de Control Sistema Seleccionen la pestaa Avanzado Accionen el botn Variables de entorno

En la lista superior pulsen nueva e ingresen estos valores: nombre: path valor: %path%;C:\FPC\2.2.2\BIN\I386_WIN32 5. Dar aceptar en todas las ventanas. Insisto que el paso anterior no debera ser necesario, ya que el instalador se encarga de realizarlo, sin embargo algunos usuarios han reportado ese problema. Por ms informacin ver: Installing under DOS or Windows en el sitio de Free Pascal.

Corrigiendo un Bug y configurando para comenzar:


Al intentar compilar por primera vez (ya veremos como se hace esto) el compilador indica un error illegal parameter -Opentium3. Este es un error que sorprende bastante ya que viene por defecto, pero bueno, es as. Por suerte es bien sencillo de solucionar. Al abrir por primera vez el ambiente de desarrollo IDE vallan al men OptionsCompiler

En el cuadro de texto Aditional Compiler Args, cambiar -Opentium3 por -Oppentium3

Vladimir Rodrguez

Programacin estructurada en Pascal


Pulsar el botn

OK

Acceder al men: OptionsSave Luego cerrar y volver a abrir el IDE. Con esto queda solucionado. En caso de presentar problemas con esto envenme un e-mail a mstrvladi@hotmail.com y les responder en breve para ayudarles a solucionarlo.

Configuracin de Range Checking e Integer Overflow:


Hace falta aadir una ltima configuracin antes de comenzar a programar, y esta consta de hacer que el compilador siempre haga un chequeo de que nuestros valores no se van fuera del rango que deben tener. Esto lo entendern en ms profundidad cuando comencemos a trabajar con arreglos, pero es conveniente tenerlo configurado desde ahora para evitarse muchos problemas. Deben ir al men Options Compiler y all presionar sobre la pestaa Generate Code. En el cuadro Code generation marcarn las opciones Range checking e Integer overflow checking tras lo cual darn OK.

Ahora s, ya estamos listos para comenzar a programar. Adelante!!!

Vladimir Rodrguez

10

Programacin estructurada en Pascal NUESTRO PRIMER PROGRAMA: HOLA MUNDO!!!


Al abrir el ambiente de desarrollo IDE vemos una pantalla azul, realmente espantosa, pero es a la que nos debemos acostumbrar si queremos aprender a programar de verdad. Existen compiladores ms bonitos, pero no son de licencia free y por tanto no los usaremos aqu. Por defecto, la primera vez que se abre el IDE lo hace con una hoja en blanco cuyo ttulo ser noname01.pas. El botn verde en la esquina superior izquierda de la pantalla es para cerrar el archivo actualmente abierto, luego veremos como trabajar con varios a la vez. La flechita verde en la esquina superior derecha es para maximizar y minimizar la ventana que contiene dicho archivo. En el borde derecho y tambin abajo tenemos barras de desplazamiento para movernos a travs del cdigo que escribiremos. Abajo, a la izquierda de la barra de desplazamiento vemos las coordenadas de nuestra posicin: fila:columna, o sea, dnde est nuestro cursor. Para cada ejemplo de programa escrito aqu analizaremos casi lnea por lnea lo que significa cada cosa para que se entienda. En principio uno se dedica a copiar programas hechos sin entender nada y poco a poco va aprendiendo hasta que se hace capaz de crear los propios. Ahora crearemos un programa muy simple que lo nico que har es imprimir en la pantalla el clsico texto Hola mundo!!!: 1 PROGRAM HolaMundo; 2 3 BEGIN 4 write(Hola mundo!!!); 5 END. Siempre la primera lnea de un programa debe comenzar con la palabra reservada PROGRAM (detallaremos lo que significa que una palabra sea reservada ms adelante) seguida por un nombre para el programa (identificador), en este caso HolaMundo. Luego de eso debe ir un punto y coma (;) para finalizar la primera lnea. Los puntos y comas funcionan como separadores y son los que indican que ha finalizado una sentencia (instruccin). Siempre luego de una instruccin va un punto y coma para finalizarla. En la segunda lnea no hemos escrito nada, esto es simplemente por una cuestin de legibilidad del cdigo. En la tercera lnea indicamos que comienza el cdigo del programa mediante la palabra reservada BEGIN. Esto no es una sentencia, por lo cual no debe finalizar con punto y coma, solo indica que a partir de all estarn las instrucciones a seguir. En la cuarta lnea indicamos al programa mediante el procedimiento write (que en ingls significa escribir) que imprima en la pantalla el texto Hola mundo!!! Siempre luego de un procedimiento write debe colocarse entre parntesis lo que queremos escribir en la pantalla, en este caso un texto especfico. Siempre que queramos que un texto aparezca en pantalla tal cual nosotros lo escribimos aqu debemos indicarlo colocando dicho texto entre comillas simples como se ve en el ejemplo. Como write implica una instruccin, luego de finalizada colocamos un punto y coma. Notar que dicha instruccin la hemos colocado ms hacia la derecha que el resto del cdigo. Esto no afecta en nada al programa, al igual que en la segunda lnea que qued vaca, sino que lo hace ms legible. A esta accin se la llama Indentacin y es muy importante. Luego detallaremos este aspecto al trabajar con programas complejos y que llevan un cdigo ms largo. La quinta y ltima lnea indica la finalizacin del programa mediante la palabra reservada END seguida inmediatamente por un punto (.). Esa es la nica palabra que terminar con un punto indicando el fin de la aplicacin. Ahora debemos compilar nuestro programa. Para ello pueden ir al men Compile Compile o presionar Alt+F9. Se les pedir un nombre para el archivo, el cual no podr contener espacios ni caracteres especiales y debe terminar con la extensin .pas. Luego de eso comenzar inmediatamente el proceso de compilacin. Si ustedes no han tenido errores de sintaxis, o sea, si han respetado el lugar adecuado para cada palabra reservada y no olvidaron ningn punto y coma o colocaron alguno donde no iba, aparecer un cartel con el mensaje Compile successful: Press any key. Esto habr creado un ejecutable (archivo de extensin exe, dicha extencin proviene de la palabra executable que en ingls significa ejecutable) en el mismo directorio en el que han guardado el archivo

Vladimir Rodrguez

11

Programacin estructurada en Pascal


.pas. Un archivo pas contiene el cdigo fuente que ustedes han escrito. Por defecto el IDE guarda un archivo en el directorio X:\fpc\2.2.2\bin\i386-win32, pero ustedes pueden especificar cualquier otro. Es conveniente que si hacen esto ninguna carpeta de su direccin posea ms de ocho caracteres como nombre ni tampoco caracteres especiales o de espacio. Ahora pueden abrir su archivo ejecutable haciendo doble clic sobre l. Tambin pueden ejecutar su programa mediante el men Run Run o presionando Ctrl+F9. En este ejemplo especfico, como en muchos otros que veremos, al correr su programa no llegarn ni a leer el texto que aparece ya que se cerrar inmediatamente. Esto no es ningn error, los programas que escribiremos finalizarn luego de terminar sus instrucciones. Claro que aprenderemos a crear aplicaciones donde uno puede seleccionar cuando salir. Si lo ejecutaron desde el IDE simplemente vallan al men Debug User screen o presionen Alt+F5. De este modo vern lo que apareci en la pantalla al ejecutar el programa. Luego presionen cualquier tecla para volver al IDE. La otra opcin es ejecutar su programa desde la lnea de comandos: Ir a Inicio Ejecutar y escriban cmd para abrir la lnea de comandos. En ella deben escribir la direccin en la que est el ejecutable que han creado y escribir el nombre exacto del mismo, que ser idntico al que ustedes usaron al guardar el archivo .pas de cdigo fuente. En mi ejemplo yo guard mi cdigo fuente con el nombre HolaMundo.pas con lo cual habr creado un ejecutable HolaMundo.exe. Para todo aquel que no lo sepa, al abrir la lnea de comandos aparece un directorio del sistema por defecto. Para cambiar de directorio en DOS se usa el comando cd (change directory) seguido de la direccin del nuevo directorio:

Al presionar enter luego de escribir esa instruccin quedaremos posicionados en el directorio donde alojamos nuestro programa. Obviamente si nosotros creamos otro directorio para trabajar con nuestras aplicaciones pascal especificaremos la ruta de dicho directorio. Una vez estamos en el directorio correcto escribimos el nombre de nuestro programa y damos enter. Enseguida se ejecutar y podremos ver sus resultados:

Del mismo modo podemos compilar nuestros programas desde la lnea de comandos. Nos posicionamos en el directorio donde radica nuestro cdigo fuente y escribimos la instruccin fpc HolaMundo.pas para este caso, de lo contrario la instruccin es fpc NombreDelArchivo.pas donde NombreDelArchivo ser el nombre con el cual guardamos nuestro cdigo fuente.

Vladimir Rodrguez

12

Programacin estructurada en Pascal Write y Writeln:


Ahora veremos un programa que imprimir dos frases de texto, una en una lnea y la otra debajo: 1 PROGRAM SalidaEstandar; 2 3 BEGIN 4 writeLn(Hice mi primer programa en Pascal.); 5 write(Logr el clsico Hola mundo.) 6 END. Al igual que antes en la primera lnea escribimos PROGRAM seguido de un identificador para el programa, finalizando la lnea con un punto y coma. En la lnea 3 indicamos el inicio de las instrucciones. En la cuarta lnea utilizamos el procedimiento writeLn para imprimir un texto en pantalla. Este procedimiento funciona exactamente igual que write. La diferencia entre la una y la otra es que write imprime algo en pantalla y deja el cursor justo al final de esa lnea. De modo contrario, writeln imprime un texto y lo deja al inicio de la lnea siguiente. As, con el ejemplo anterior obtenemos como salida: Hice mi primer programa en Pascal. Logr el clsico Hola mundo. Noten que la ltima sentencia no finaliza con punto y coma. Esto es porque al final del programa cuando dictas la ltima instruccin no hace falta separarla de ninguna otra y es posible omitir el punto y coma, sin embargo no est mal si lo colocan. Como ya habrn notado, al ir escribiendo cdigo el IDE ir coloreando las palabras. Aquellas que son reservadas sern de color blanco (writeln y readln son reservadas pero no se colorean, lo mismo suceder con otras tantas), el texto que ser impreso tal cual, o sea, el que est entre comillas simples, se ve en celeste, lo dems se ve amarillo, y as suceder con otras cosas. Los procedimientos write y writeln imprimen informacin en pantalla, en lo que llamamos salida estndar, o sea, la salida de la lnea de comandos. Llamamos salida ya que es informacin entregada por el programa. Del mismo modo la llamaremos entrada estndar cuando sea usada para ingresar informacin al programa. Pascal no es un lenguaje que diferencie entre maysculas o minsculas en su cdigo fuente, por lo cual escribir writeln, WRITELN, WrItElN o como sea, es exactamente igual. Lo mismo sucede con los identificadores, si ustedes llaman a su programa SALIDAESTANDAR, salidaestandar, SaliDaesTandar o como sea, da exactamente lo mismo. Esto se aplica para las dems palabras reservadas. Noten que si en un texto que se imprimir en pantalla ustedes cambian las maysculas y las minsculas s se vern las diferencias.

Vladimir Rodrguez

13

Programacin estructurada en Pascal Introduccin a las variables:


Muy bien, hasta ahora vimos dos ejemplos de programas que ejecutan una o dos instrucciones para mostrar informacin en pantalla. Sin embargo, normalmente hace falta ingresar informacin a un programa para que con ella, este realice una o varias tareas. A continuacin veremos el ejemplo de un programa que pedir a un usuario que ingrese su nombre y luego le saludar nombrndolo: 1 2 3 4 5 6 7 8 9 10 PROGRAM EjemploVariable; Var nombre: String; BEGIN write(Ingresa tu nombre: ); readln(nombre); writeln(Hola ,nombre); END.

Hemos comenzado como siempre escribiendo PROGRAM seguido de un identificador para nuestro programa y un punto y coma. En la tercera lnea vemos la palabra reservada VAR, la cual indica que a continuacin se declararn todas las variables que usar nuestro programa en sus tareas. Una variable guarda informacin de algn tipo especfico y luego usa esta para realizar diferentes acciones, incluso modificar su valor. Nosotros podremos modificar el contenido de una variable siempre que queramos (detallaremos esto ms adelante) y en cualquier momento dentro de nuestro programa. Para declarar una variable, luego de la palabra VAR, le damos un nombre (identificador) a la variable y definimos de qu tipo ser. La sintaxis para hacerlo es la siguiente: NombreDeLaVariable: tipo; en nuestro ejemplo, en la lnea 4 hemos declarado una variable llamada nombre del tipo string, o sea, una variable que contendr cadenas de caracteres. String es una palabra reservada de pascal y corresponde a un tipo primitivo del mismo. Todo lo que sea del tipo String almacenar cadenas de caracteres. Nosotros no usaremos mucho este tipo en general ya que no resulta muy til a los efectos de este manual, pero an as sirve conocerlo. En la lnea 6 indicamos el inicio del programa. Como ven, la declaracin de variables se hace antes de iniciar el programa. Esto es porque el compilador primero asigna la memoria RAM que necesitar para almacenar cada variable y luego comienza con la ejecucin del programa. Las variables declaradas se guardan en celdas de memoria aunque no se usen, por lo cual no conviene declarar variables inservibles. En la lnea 7 usamos write para imprimir un mensaje al usuario y dejar el cursor a continuacin del mensaje, ya que all se escribir el nombre. En la octava lnea utilizamos el procedimiento readln para leer informacin de la entrada estndar e indicamos entre parntesis que dicha informacin debe ser almacenada en la variable nombre (la informacin se leer al presionar enter). Siempre luego del procedimiento read o readln se especifica entre parntesis la o las variables que guardarn la informacin leda, de lo contrario, el programa no guardar ningn registro de la informacin administrada por el usuario y continuar su curso. En la novena lnea utilizamos el procedimiento writeln al cual le pasamos dos campos de informacin esta vez, primero el texto que debe imprimir y luego, separado por una coma, el nombre de la variable cuya informacin queremos que aparezca en pantalla. Cuando uno necesita imprimir varias cosas con un solo procedimiento write o writeln debe separar los campos con una coma. En este caso, un campo contiene el texto y el otro la variable nombre. Cuando se especifica el nombre de una variable dentro de un campo de estos procedimientos, lo que aparecer en pantalla es el contenido de la variable. En este caso la variable nombre guardar la palabra que nosotros escribamos y luego ser lo que aparezca en pantalla al imprimir su contenido. Ejemplo de ejecucin: Ingresa tu nombre: Vladimir Hola Vladimir Al igual que con write y writeln, la diferencia entre read y readln es que la primera lee informacin de la entrada estndar y deja el cursor al final de la lnea en que la informacin fue ingresada. La segunda deja el cursor justo al inicio de la lnea siguiente. Pueden probar a escribir el programa anterior intercambiando estas funciones para ver el resultado y comprenderlo mejor. Notas: No declarar una variable luego de la palabra VAR es un error de sintaxis. No usar los dos puntos (:) para luego indicar el tipo de la variable es un error de sintaxis. Dos variables no pueden llamarse de la misma manera ni tampoco pueden llamarse igual que el programa, dicho de otra manera, no pueden repetirse dos identificadores, eso es un error de sintaxis.

Vladimir Rodrguez

14

Programacin estructurada en Pascal


Ejemplo de asignacin: Con el siguiente programa veremos como usar variables numricas y cmo asignarle un valor especfico a una variable as como tambin a realizar operaciones entre ellas calculando el rea de un tringulo: 1 PROGRAM AraTriangulo; 2 3 Var 4 base, altura: integer; 5 area: real; 6 7 BEGIN 8 Write(Ingresa la base: ); 9 Readln(base); 10 Write(Ingresa la altura: ); 11 Readln(altura); 12 13 area:= base*altura/2; 14 15 Writeln(El rea del tringulo es: ,area:1:2); 16 END. Este programa utiliza tres variables: base, altura y area, para calcular el rea de un tringulo. La base y la altura del mismo son ingresadas por el usuario, y el valor de area se asigna dentro del programa. Esta vez tenemos dos variables del tipo integer, o sea que almacenarn nmeros enteros y una del tipo real, o sea que almacenar nmeros reales. Como ven es posible declarar ms de una variable del mismo tipo en una sola sentencia, simplemente separndolas por comas (,) y asignando el tipo al final, como hemos hecho en la lnea 4. Puede, si se desea, declararse cada variable por separado. En la lnea 8 imprimimos una instruccin para el usuario y en la lnea 9 indicamos al programa que lea de la entrada lo que el usuario ingrese y lo guarde dentro de la variable base. En la lnea 10 imprimimos otra instruccin al usuario y en la 11 leemos un valor y lo guardamos en la variable altura. En la lnea 13 de nuestro programa le asignamos a la variable area mediante el uso del smbolo de asignacin (:=) el valor del resultado de multiplicar el valor de base por el valor de altura y dividirlo entre 2. O sea, estamos multiplicando ambas variables ya que contienen nmeros. El smbolo para multiplicar es el asterisco (*) y para la divisin la barra (/). En la lnea 15 usamos writeln a la cual le pasamos dos campos de informacin, uno con el texto a imprimir y otro con la variable cuyo valor debe mostrarse con modificadores de decimales (ya explicar esto). Este programa podra haberse hecho sin la variable area y la lnea 15 quedara as Writeln (El rea del tringulo es: ,base*altura/2:1:2); Como ven, es posible colocar expresiones en los campos de write y writeln. Los nmero enteros no contienen cifras despus de la coma y los reales s pueden contenerlas. La variable area es del tipo real por lo cual al imprimir su contenido este se mostrar con valores decimales y exponente en base 10. Por ejemplo si su valor es 50, se imprimir as 5.00000000000000E+001. Esto equivale a 5x10 1. Los modificadores :1:2 indican en su primer valor el nmero mnimo de caracteres que toleraremos en el resultado (1) y el segundo valor indica cuantas cifras luego de la coma queremos que aparezcan (2). Con esto, el valor anterior se ver como 50.00. Leer ms de una variable a la vez: El programa anterior podra haber sido escrito de la siguiente manera: 1 PROGRAM AraTriangulo; 2 3 Var 4 base, altura: integer; 5 area: real; 6 7 BEGIN 8 Write(Ingresa base y la altura separadas por un espacio: ); 9 Readln(base,altura); 10 11 area:= base*altura/2; 12 13 Writeln(El rea del tringulo es: ,area:1:2); 14 END.

Vladimir Rodrguez

15

Programacin estructurada en Pascal


Como pueden observar bsicamente es lo mismo, con la nica diferencia crucial de que esta vez, en la lnea 9, indicamos al programa mediante el procedimiento readln que lea dos variables a la vez. Esto siempre es posible. Solo deben colocarse entre los parntesis los nombres de las variables a leer separados por comas. Pueden ser variables de distinto tipo. En este caso especfico ambas son integer. Cuando se ingresen los datos para la entrada estndar deben separarse por un espacio. Si el usuario ingresa solo un dato ste se asignar a la primera variable que aparezca dentro de los parntesis y el programa quedar esperando el siguiente valor. Del mismo modo pueden imprimirse varias variables a la vez ingresando los nombres de cada variable separados por comas dentro de los parntesis de un procedimiento write o writeln. Ejercicio: Realicen un programa que calcule el rea y el permetro de un rectngulo. Recuerden que el rea de un rectngulo se calcula como base*altura y su permetro como base*2+altura*2. El programa recibir de la entrada estndar la base y la altura y mostrar como salida un mensaje con el rea y otro, debajo, con el permetro. Estos mensajes deben estar separados al menos por una lnea en blanco de los mensajes de instrucciones para el usuario. Ejemplo de ejecucin: Ingrese la base: 10 Ingrese la altura: 6 El rea de rectngulo es: 60 El permetro del rectngulo es: 32 Deben ser capaces de realizar este ejercicio antes de continuar. Si desean saber la solucin escrbanme a mstrvladi@hotmail.com .

Vladimir Rodrguez

16

Programacin estructurada en Pascal Introduccin a la compatibilidad de tipos:


En el ejemplo anterior tenemos dos variables del tipo integer (enteros) y una del tipo real (reales). Una variable integer no puede contener reales pero una real s puede contener enteros. Si en el ejemplo anterior el usuario ingresa para base un nmero real no entero (por ejemplo 1.5) el programa intentar guardar este valor en una variable entera y no podr por lo cual se producir un error en tiempo de ejecucin que har que el programa finalice abruptamente. Si base fuera del tipo real y se le pasara un valor integer (por ejemplo 4) no habra problema ya que el programa transformar el entero a real, o sea el 4 ser 4.0. Esto no afecta la informacin ya que 4 y 4.0 son exactamente el mismo valor, pero no hay forma de pasar un real a entero sin modificar este de alguna manera, ya sea truncndolo (dejar un 1.5 en 1) o redondendolo de alguna forma. Si la variable area en nuestro programa fuera tambin del tipo entero, tendramos un error en tiempo de compilacin al intentar asignarle el valor de multiplicar base por altura y dividir esto entre dos, ya que la operacin (/) devuelve como valor un real. El compilador detectara esto y cancelara su tarea indicando que hay un error en la compatibilidad de tipos ya que se quiere asignar un real a un entero. Del mismo modo, si a variables reales o enteras se les asigna una cadena de caracteres como entrada, tendremos un error en tiempo de ejecucin ya que valores numricos no son compatibles con cadenas de caracteres. Lo ms conveniente para el programa anterior sera declarar todas las variables como reales. Esto soluciona el problema de la compatibilidad de tipos numricos, aunque an tenemos el problema de si el usuario ingresa un carcter que no sea un nmero en las entradas de este programa. A la tarea de detectar todas las posibles situaciones que puede enfrentar nuestro programa al ser usado y sus consecuencias se le llama Captura de errores y es una de las tareas ms difciles ya que es fcil que se nos pase por alto algn caso, y ms an cuando nuestro programa es muy complejo. A medida que avancemos veremos cmo enfrentar estas situaciones.

Vladimir Rodrguez

17

Programacin estructurada en Pascal Errores en tiempo de Ejecucin y errores en tiempo de Compilacin:


Luego de escribir el cdigo siempre intentamos compilarlo para generar nuestro ejecutable y ver los resultados de nuestro trabajo. Mientras el programa se compila decimos que estamos en tiempo de compilacin. Los errores que pueden sufrirse aqu son generalmente de sintaxis y de compatibilidad de tipos. Cuando hay un error en tiempo de compilacin el compilador se detiene y nos indica el lugar donde encontr el error proporcionndonos adems alguna informacin acerca de por qu se produjo. Estos son los errores ms fciles de arreglar ya que son detectables fcilmente. Ahora bien, que un programa compile perfectamente no nos dice que no tenga errores. Cuando ejecutamos un programa decimos que estamos en tiempo de ejecucin. Los errores en tiempo de ejecucin provocan que el programa se cuelgue, termine inesperadamente perdindose toda la informacin que tenamos o que muestre resultados inesperados. Estos errores son los menos deseados y los ms difciles de detectar ya que se deben a errores en nuestras instrucciones al programa. Veamos un ejemplo sencillo, un programa que divide dos nmeros: 1 PROGRAM dividir; 2 3 Var 4 a, b: real; 5 6 BEGIN 7 Write(Ingrese un nmero: ); 8 Readln(a); 9 Write(Ingresa otro nmero: ); 10 Readln(b); 11 12 Wtieln(El resultado de la divisin es: ,a/b:1:2); 13 END. Supongamos que sabemos que nuestros usuarios solo ingresarn nmeros a nuestro programa. Cul sera el problema entonces? Ese programa compila perfectamente y solo ingresarn nmeros, no habra error posible. Pero qu pasa si cuando se ingresa el valor para b el usuario ingresa el valor 0? Supongamos que la ejecucin fue as: Ingrese un nmero: 5 Ingrese otro nmero: 0 Qu debera mostrar nuestro programa? Al llegar a la lnea 12 he intentar la divisin de a/b, o sea 5/0, no podr ya que la divisin entre 0 no est definida matemticamente y el programa producir un error y se terminar su ejecucin. Lo correcto sera que si el usuario ingresa un 0 para la variable b el programa nos muestre un mensaje de error y nos vuelva a pedir un nuevo valor. Cuando veamos estructuras de control veremos como tomar distintos caminos segn las condiciones que se dan.

Vladimir Rodrguez

18

Programacin estructurada en Pascal Palabras reservadas:


Las palabras reservadas por Pascal son aquellas que indican alguna funcin especfica del lenguaje, como por ejemplo, write indica que algo se desplegar en pantalla y readln que el usuario ingresar alguna informacin. Que una palabra sea reservada indica que esta no puede utilizarse como identificador, o sea, uno no puede crear un programa llamado Writeln o Var, o una variable llamada Readln. Utilizar palabras reservadas indebidamente es un error de sintaxis. He aqu una lista de casi todas las palabras reservadas en pascal:

AND ARRAY BEGIN CASE CONST DIV DO DOWNTO ELSE END FILE FOR FUNCTION GOTO IF IN LABEL MOD NIL NOT OF OR PACKED PROCEDURE PROGRAM

RECORD REPEAT SET THEN TO TYPE UNTIL VAR WHILE WITH ABS ARCTAN BOOLEAN CHAR CHR COS DISPOSE EOF EOLN EXP FALSE GET INPUT INTEGER LN

MAXINT NEW NIL ODD ORD OUTPUT PACK PAGE PRED PUT READ READLN RESET REWRITE ROUND SIN SQR SQRT SUCC TEXT TRUE TRUNC UNPACK WRITE WRITELN

Vladimir Rodrguez

19

Programacin estructurada en Pascal Identificadores:


Como ya hemos visto, utilizamos identificadores para nombrar a nuestro programa y a nuestras variables. En efecto, un identificador es un nombre que nosotros asignamos a nuestros objetos en el programa para identificarlos luego mediante ese nombre. Usaremos identificadores para nombrar variables, constantes, tipos, parmetros, funciones, procedimientos y punteros entre otras cosas. Un identificador puede ser cualquier cadena de caracteres alfanumricos o de subrayado que comience al menos con una letra. No puede contener espacios ni caracteres especiales as como tampoco puede ser igual a una palabra reservada. De este modo, identificadores vlidos pueden ser: Abuela, ABuela2, Ejemplo_de_identificador, E2B214, etc. Identificadores invlidos podran ser: 1Abuela, Abuela 2, Ejemplo de Identificador, Abk$, Variable(), pascal, var, program, etc.

Tipos de datos:
Ordinales: Son aquellos que, dado un elemento, podemos saber cual es el siguiente y/o el anterior adems de que poseen una cantidad finita de elementos. Por ejemplo dado un nmero entero sabemos que el siguiente es ese nmero ms uno y el anterior es el nmero menos uno. Dado el 5 su predecesor es el 4 y su sucesor es el 6. Integer Nmeros enteros, sin ninguna cifra decimal. Char Caracteres. Boolean Valores lgicos, pueden valer True o False. Enumerados Definido por el programador. Subrango Definido por el programador. Para estos tipos llamados Ordinales tenemos tres funciones predefinidas por Pascal que suelen ser tiles: Pred(valor_de_tipo_ordinal) Devuelve el predecesor para cualquier valor de tipo ordinal excepto si ste es el primero de todos. En este caso tenemos un error en tiempo de ejecucin. Succ(valor_de_tipo_ordinal) Devuelve el sucesor para cualquier valor de tipo ordinal excepto si ste es el ltimo de todos. En este caso tenemos un error en tiempo de ejecucin. Ord(valor_de_tipo_ordinal) Devuelve el ordinal para cualquier valor de tipo ordinal. Ya hablaremos de esto ms tarde, al igual que de las dos funciones anteriores. Reales: Solo tenemos el tipo real para esta categora. Las funciones anteriores no funcionan con valores de tipo real ya que es imposible saber, dado un real, cual es su sucesor o su predecesor. Estructurados: Forman estructuras de datos, en general, bastante complejas. String Array Record File Set Cadena de caracteres. Tablas de datos (String es un array de caracteres). Registros de datos. Secuencias de datos (No trabajaremos con este tipo). Conjuntos de datos.

Punteros: Hablaremos de ellos al final de este tutorial. Notas: El mayor entero posible es identificado por la palabra reservada MAXINT, la cual es una constante (hablaremos de estas ms adelante).

Operadores en pascal: Veamos los operadores aritmticos de Pascal, los cuales son usados para crear expresiones matemticas y realizar clculos:

Vladimir Rodrguez

20

Programacin estructurada en Pascal


Operador * A/B / A div B DIV A mod B MOD A+B + A-B A menos B A ms B Resto de A dividido B (divisin entera) A dividido B (divisin entera) A dividido B Expresin A*B Significado A por B Descripcin Realiza el producto de A por B. A y B pueden ser reales o enteros. Basta con que uno sea real para que el resultado sea un real. Realiza la divisin entre A y B. Devuelve como resultado un real. Realiza la divisin entera entre A y B. Devuelve como resultado el cociente, por tanto A y B han de ser enteros. Realiza la divisin entera entre A y B y devuelve como resultado el resto. A y B deben ser enteros. Realiza la suma de A ms B. Basta con que uno de los sumandos sea real para que devuelva un real. Realiza la resta de A menos B. Basta con que uno de los restando sea real para que devuelva un real.

Precedencia de operadores: Dada una expresin matemtica donde se combinen varios de estos operadores, al igual que en el lgebra comn, se realizarn primero los productos (*), las divisiones (div), (mod) y (/) y luego las sumas (+) y restas (-). Para quebrar esta precedencia de quin va primero que quin, se utilizan los parntesis. Ejemplo: A+B*C En este caso aparece primero la suma y luego un producto. Sin embargo el producto tiene precedencia ante la suma y se evaluar primero B*C para luego sumar ese resultado con A. Si se quisiera realizar primero la suma habra que utilizar parntesis y escribir aquella expresin como (A+B)*C. Ahora s se realizar primero la suma y luego el producto ya que los parntesis tienen la precedencia absoluta excepto si existen funciones que deben evaluarse dentro.

Funciones matemticas de pascal: Pascal nos provee de varias funciones matemticas predefinidas para realizar algunos clculos comunes. En los siguientes ejemplos la letra x simbolizar un nmero o expresin del tipo adecuado para la funcin en cuestin: ABS(x) SQR(x) SQRT(x) SIN(x) ARCTAN(x) EXP(x) LN(x) Calcula el valor absoluto de X. X debe ser integer o real. El resultado es del mismo tipo que X. Calcula el cuadrado de X. X debe ser integer o real. El resultado es del mismo tipo que X. Calcula la raz cuadrada de X siendo X un real o entero mayor o igual que 0. El resultado es un del tipo real. Calcula el seno de X expresado en radianes. X debe ser integer o real. El resultado es del tipo real. Calcula el arco tangente de X. X debe ser integer o real. El resultado es del tipo real. Calcula la exponencial de X (ex donde e= 2.7182818). X debe ser integer o real. El resultado es del tipo real. Calcula el logaritmo neperiano (base e) de X siendo X mayor que cero. X debe ser integer o real. El resultado es del tipo real. Suprime la parte decimal de X dejando solo el valor anterior a la coma. X debe ser real. El resultado es del tipo integer. Redondea el valor de X al entero ms prximo. X debe ser real. El resultado es del tipo integer. Obtiene el nmero de orden de X dentro de un conjunto de valores definidos por su tipo. X debe ser de un tipo ordinal. El resultado es de tipo integer.

TRUNC(x) ROUND(x) ORD(x)

Vladimir Rodrguez

21

Programacin estructurada en Pascal


CHR(x) Devuelve el caracter cuyo nmero ordinal es X. El tipo de X debe ser integer. El resultado es de tipo char.

Un ejemplo del uso de DIV y MOD. Introduccin a los comentarios: Se nos plantea el siguiente problema. Dado un nmero entero de cuatro cifras que ser ledo desde la entrada estndar se nos pide que hagamos la suma de sus cifras. Por ejemplo, si el usuario ingresa el nmero 5648 el programa debe realizar la suma de 5+6+4+8 y mostrar el resultado. Se asume que el usuario ingresar efectivamente un nmero de cuatro cifras. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 {El siguiente programa desglosar un nmero de cuatro cifras en sus cuatro nmeros distintos, uno por cada cifra y realizar la suma entre ellas} PROGRAM SumaCifras; Var numero: integer; //El valor que ser ledo. c1, c2, c3, c4: integer;//Una variable para cada cifra. BEGIN write('Ingresa un nmero de cuatro cifras: '); readln(numero); //Leemos el nmero de 4 cifras. (*Asignamos a cada variable el valor de la cifra que le corresponde*) c1:= numero mod 10; c2:= (numero mod 100) div 10; c3:= (numero mod 1000) div 100; c4:= numero div 1000;

//Mostramos el resultado al usuario. write('El resultado de sumar ',c4,'+',c3,'+',c2,'+',c1,' es: ' ,c1+c2+c3+c4); 22 END. Este es nuestro primer programa en el que vemos el uso de comentarios. Los comentarios son anotaciones hechas por el propio programador para ir explicando lo que se va realizando en su cdigo. Esto es debido a que normalmente el software se desarrolla en equipo y resulta imprescindible que otros lean el cdigo que uno escribe y sean capaces de entenderlo. Los comentarios son omitidos por el compilador por lo cual no afectan en absoluto al funcionamiento del programa, solo son una documentacin explicativa. Existen dos tipos de comentarios, los comentarios multilnea y los comentarios de fin de lnea. Los primeros pueden abrirse con { y cerrarse con } tal como se ve en las primeras tres lneas de nuestro programa, o abrirse con (* y cerrarse con *) tal como se ve en la lnea 14 de nuestro programa. Un comentario multilnea puede ocupar una o ms lneas de cdigo, tantas como sea necesario. Los comentarios de fin de lnea se abren con // y no requieren ningn smbolo de cierre ya que, como su nombre lo indica, finalizan al terminar la lnea en que aparecen. Podemos verlos en las lneas 7, 8, 12 y 20 de nuestro ejemplo. En el IDE se vern de color gris. Ahora miremos un poco la lgica de nuestro programa, como usando mod y div solamente, puede desglosarse un nmero en sus respectivas cifras. En la lnea 12 leemos de la entrada estndar un valor y lo guardamos dentro de numero. Luego, en la lnea 15, mediante el smbolo de asignacin := le damos a c1 el valor de la primera cifra de nuestro nmero. Fjense que si uno tiene un nmero de ms de una cifra y lo divide entre 10, el resto de esa divisin ser la primera cifra si leemos de derecha a izquierda. Teniendo por ejemplo el 1456, si dividimos ese nmero entre 10 (divisin entera, sin llevarlo a decimales) obtenemos como resto el 6 y como resultado el 145. En la lnea 13 obtenemos el resto de dividir nuestro nmero entre 100, eso da como resultado el entero formado por las dos primeras cifras (de derecha a izquierda) y luego (notar que esta operacin est entre parntesis para que se realice primero) mediante div obtenemos el cociente de dividir ese nmero entre 10. Por ejemplo, si tenemos 1456 y lo dividimos entre 100, el resultado es 14 y el resto 56. Teniendo el resto, al dividirlo entre 10 tenemos como resultado el 5 y como resto el 6. De este modo en las lneas 17 y 18 obtenemos las ltimas dos cifras de nuestro nmero. Ahora las variables c1, c2, c3 y c4 contienen cada una los valores de una cifra de nuestro valor inicial. En la lnea nmero 21 mostramos mediante el procedimiento write los resultados de nuestro programa.

Vladimir Rodrguez

22

Programacin estructurada en Pascal Introduccin a las constantes:


Al igual que podemos definirnos variables, que son objetos cuyos valores van cambiando a lo largo del programa, tambin podemos definirnos constantes, que sern objetos cuyo valor no cambiar nunca a lo largo del programa. Veremos un ejemplo en el cual intentar hacerles entender la necesidad de las constantes. El siguiente programa pedir como entrada en reales el precio sin IVA de cinco productos que estn a la venta en un almacn. Luego mostrar el precio de dichos productos con el IVA agregado. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 PROGRAM preciosIVA; Const iva= 23; Var harina, leche, azucar, sal, arroz: real;//Precios de los productos. porcentaje: real; //Para calcular cuanto se debe sumar al precio. BEGIN //Mostramos mensajes al usuario y leemos los datos desde la entrada. write('Precio HARINA : '); readln(harina); write('Precio LECHE : '); readln(leche); write('Precio AZUCAR : '); readln(azucar); write('Precio SAL : '); readln(sal); write('Presto ARRZ : '); readln(arroz); //Dejamos una lnea en blanco. writeln; //Calculamos el porcentaje de IVA para harina. porcentaje:= harina*iva/100; //Mostramos el nuevo precio al usuario. writeln('HARINA + IVA : ',harina+porcentaje:2:2); //Calculamos el porcentaje de IVA para leche. porcentaje:= leche*iva/100; //Mostramos el nuevo precio al usuario. writeln('LECHE + IVA : ',leche+porcentaje:2:2); //Calculamos el porcentaje de IVA para azucar. porcentaje:= azucar*iva/100; //Mostramos el nuevo precio al usuario. writeln('AZUCAR + IVA : ',azucar+porcentaje:2:2); //Calculamos el porcentaje de IVA para sal. porcentaje:= sal*iva/100; //Mostramos el nuevo precio al usuario. writeln('SAL + IVA : ',sal+porcentaje:2:2); //Calculamos el porcentaje de IVA para arroz. porcentaje:= arroz*iva/100; //Mostramos el nuevo precio al usuario. writeln('ARROZ + IVA : ',arroz+porcentaje:2:2); END.

Bien, en la lnea 3 vemos la palabra reservada const, que indica que desde all se declararn constantes. La sintaxis para declaracin de constantes es NombreDeLaConstante= valor; donde valor representa un valor de algn tipo primitivo de pascal (integer, real, char, string entre algn otro). El nombre de la constante es un identificador. En este caso, en la lnea 4 del programa hemos declarado la constante iva y le hemos dado el valor 23, que representa el 23% que vale el IVA en mi pas. Notar que las constantes se declaran antes que las variables.

Vladimir Rodrguez

23

Programacin estructurada en Pascal


Luego, en las lneas 7 y 8 declaramos las variables del programa, una para el precio de cada producto y una para calcular el porcentaje de IVA que le corresponde al precio de cada producto para luego sumrselo al mismo. En las lneas 13 a 22 inclusive, mostramos mensajes al usuario y leemos los valores de las entradas para cada producto. Luego, en la lnea 25 indicamos mediante el procedimiento writeln que queremos dejar una lnea en blanco. Esto se hace llamando al procedimiento sin pasarle campos entre parntesis. En la lnea 28 calculamos el porcentaje de IVA para la harina asignando este valor a la variable porcentaje. Esta operacin es simple. Si uno tiene un valor y quiere saber un porcentaje de ese valor simplemente multiplica dicho valor por el porcentaje que quiere obtener y divide el resultado entre 100. Por ejemplo, si tenemos el nmero 278 y queremos saber el 15% de ese nmero simplemente realizamos la operacin 278x15/100 lo cual nos dara 41,7. Ese valor corresponde al 15% de 278. De este modo calculamos el porcentaje de IVA para cada producto multiplicando su precio por el valor de la constante iva y dividiendo entre 100. En la lnea 30 mostramos un mensaje al usuario y el precio de la harina ms el porcentaje de IVA del mismo, en este caso ms un 23%. Repetimos esto hasta el final de la aplicacin. Notar que siempre usamos la variable porcentaje para calcular el 23% de cada precio. El smbolo de asignacin (:=) borra el contenido anterior de la variable y asigna el nuevo, o sea, la sobrescribe. Ahora veamos el mismo programa pero sin el uso de la constante iva: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 PROGRAM preciosIVA; Var harina, leche, azucar, sal, arroz: real;//Precios de los productos. porcentaje: real; //Para calcular cuanto se debe sumar al precio. BEGIN //Mostramos mensajes al usuario y leemos los datos desde la entrada. write('Precio HARINA : '); readln(harina); write('Precio LECHE : '); readln(leche); write('Precio AZUCAR : '); readln(azucar); write('Precio SAL : '); readln(sal); write('Precio ARRZ : '); readln(arroz); //Dejamos una lnea en blanco. writeln; //Calculamos el porcentaje de IVA para harina. porcentaje:= harina*23/100; //Mostramos el nuevo precio al usuario. writeln('HARINA + IVA : ',harina+porcentaje:2:2); //Calculamos el porcentaje de IVA para leche. porcentaje:= leche*23/100; //Mostramos el nuevo precio al usuario. writeln('LECHE + IVA : ',leche+porcentaje:2:2); //Calculamos el porcentaje de IVA para azucar. porcentaje:= azucar*23/100; //Mostramos el nuevo precio al usuario. writeln('AZUCAR + IVA : ',azucar+porcentaje:2:2); //Calculamos el porcentaje de IVA para sal. porcentaje:= sal*23/100; //Mostramos el nuevo precio al usuario. writeln('SAL + IVA : ',sal+porcentaje:2:2); //Calculamos el porcentaje de IVA para arroz. porcentaje:= arroz*23/100; //Mostramos el nuevo precio al usuario. writeln('ARROZ + IVA : ',arroz+porcentaje:2:2); END.

Vladimir Rodrguez

24

Programacin estructurada en Pascal


Esta versin funciona exactamente igual a la anterior, con la diferencia de que en el cdigo, donde antes tenamos el identificador iva ahora hay un 23. Ahora imaginen la siguiente situacin: el valor de IVA cambia en un momento dado y se les pide que reestructuren su programa para el nuevo valor de IVA. Si ustedes hicieron su programa tal como esta ltima versin debern buscar en su cdigo cada una de las veces en que usaron el 23 para calcular el porcentaje de IVA y cambiarlo por el nuevo valor, mientras que en la versin con constante solo es ir a donde est declarada iva y modificar ah su valor con lo cual no sera necesario tocar ms nada del cdigo. Esta accin puede realizarla hasta alguien que no haya sido el propio programador, mientras que en el cdigo sin constante, si uno no fue quien program deber primero sentarse a leer y entender el cdigo hasta que pueda efectivamente hacer una bsqueda de los lugares donde se realiz el clculo del IVA para poder modificarlos. En este ejemplo no resulta difcil modificar todos los 23 que hay, pero imaginen una base de datos de un supermercado en el cual hay miles de productos y precios diferentes. Sera mejor buscar y cambiar todos y cada uno de los valores en que usamos el 23, o sera mejor declarar una constante y solo cambiar un 23? Normalmente los cdigos son muy extensos y complicados, por lo cual una tarea de revisin total y bsqueda exhaustiva sera muy tediosa y difcil, adems de que es muy probable que se nos pase por alto alguna expresin a modificar. El uso de constantes es muy recomendable cuando se va a usar un mismo valor muchas veces. Nota: No puede usarse una constante a la izquierda de una asignacin. Por ejemplo sera errneo escribir iva:= 10; ya que iva no puede ser modificada. Esto es un error de sintaxis.

Vladimir Rodrguez

25

Programacin estructurada en Pascal Booleanos:


El tipo boolean resulta muy extrao al principio. Solo contiene dos valores posibles: True y False. O sea, una variable del tipo boolean solo puede ser verdadera o falsa. Aunque en principio uno no puede imaginarse para qu puede servir una variable de este tipo, realmente resultarn muy tiles ms adelante, cuando tengamos que comenzar a darle condiciones a nuestro programa para que tome distintos caminos de ejecucin. No es posible hacer write ni read de una variable boolean.

Algunas notas: El punto y coma acta como separador. Nosotros acostumbramos a escribir una instruccin por lnea por una cuestin de legibilidad del cdigo, sin embargo al compilador eso no le importa al igual que tampoco la sangra (indentacin) que dejemos. De este modo resultar lo mismo escribir Writeln(Hola mundo); Readln(variable); que escribir writeln(Hola mundo); readln(variable); Ejercicios: Antes de continuar debern ser capaces de realizar la gran mayora de los ejercicios que aparecern en los links a continuacin. Estos los dirigirn a una pgina de Facultad de Ingeniera y los ejercicios estn pensados para reforzar todo lo que yo ya les he explicado hasta aqu. La mayora se resuelve de forma dinmica con la pgina WEB con lo cual ustedes podrn verificar sus resultados al instante. Reitero, traten de resolver la mayor parte de esos ejercicios antes de continuar o de lo contrario no podrn desempearse bien en los temas que trataremos en lo que sigue del tutorial. Prctico 1: http://www.fing.edu.uy/inco/cursos/prog1/pm/field.php/Practicos/Practico1 Prctico 2: http://www.fing.edu.uy/inco/cursos/prog1/pm/field.php/Practicos/Practico2 En caso de tener problemas con estos enlaces o con las pginas a las que estos los llevan envenme un e-mail a mstrvladi@hotmail.com y les ayudar a la brevedad.

Vladimir Rodrguez

26

Programacin estructurada en Pascal

SEGUNDA PARTE

Seleccin y Repeticin

Vladimir Rodrguez

27

Programacin estructurada en Pascal Introduccin:


En esta seccin del tutorial aprenderemos a usar secuencias de seleccin para indicarle al programa qu camino ha de tomar en funcin de ciertas condiciones dadas as como tambin aprenderemos secuencias de repeticin para indicarle al programa que debe volver a ejecutar cierto fragmento de cdigo una cantidad de veces dada, o no. Es aqu donde la programacin comienza a complicarse un poco y comenzamos a tener verdaderos dolores de cabeza cuando nuestros programas no hacen lo que nosotros queremos. Es muy comn que, en las secuencias de repeticin, nunca se den las condiciones necesarias para finalizar la repeticin y nuestro programa entre en un bucle infinito (loop) y quede colgado realizando la misma tarea hasta que nosotros lo cerremos o se bloquee el sistema. Tambin es muy comn que olvidemos alguna condicin necesaria para que el programa tome un camino especfico y por lo tanto funcione errneamente, o que ni se nos haya cruzado por la cabeza que el usuario podra haber ingresado tal o cual instruccin y esto genere muchos errores en la ejecucin de nuestro programa. Por estos motivos es que cuando uno crea un programa debe probarlo con la peor intencin posible para detectar la mayora de los errores que puedan aparecer. Dedicar una seccin entera para hablar de la prueba de programas. El ambiente de desarrollo IDE de Free Pascal tiene incluido un depurador (debugger). Esta es una herramienta que nos permitir ver la ejecucin de nuestro programa paso a paso y visualizar en una pequea ventana los valores que nuestras variables van tomando para as, poder detectar errores que de otro modo sera casi imposible. Aprenderemos a usar esta herramienta en la pgina 42 de este tutorial. Conviene leerla cuando lleguen a ella, pero si necesitan encontrar algn error en los programas que van desarrollando lanla cuando quieran.

Vladimir Rodrguez

28

Programacin estructurada en Pascal Seleccin. Instruccin IFTHEN e IFTHENELSE:


Como ya hemos visto que se vuelve necesario tomar distintos caminos segn lo requieran las circunstancias. Por ejemplo, en nuestro programa que divida dos cifras (pgina 18) haca falta mostrar un mensaje de error al usuario en caso de que este ingresara como segundo valor un 0 ya que esto causara un error en tiempo de ejecucin, y en caso contrario simplemente mostrar el resultado de la divisin. Aqu entra en juego la instruccin de seleccin ifthen que en ingls significa (sientonces). Su sintaxis es la siguiente: If condicin then Instruccin; Supongo que debo decir que IF, THEN y ELSE son palabras reservadas. Veamos un ejemplo sencillo en el cual un programa pedir que se ingrese una edad a un usuario y si esta es mayor a 50 aos le dir que es un viejo. 1 PROGRAM viejo; 2 3 Var 4 edad: integer; //Variable para guardar la edad. 5 6 BEGIN 7 //Mostramos mensaje y leemos la edad. 8 write('Ingrese su edad: '); 9 readln(edad); 10 11 //Mostramos lo mismo que ya ingres. 12 writeln('Usted tiene ',edad,' aos.'); 13 14 //Si tiene ms de 50 aos le decimos viejo. 15 If edad>50 then 16 writeln('Usted es un viejo'); 17 18 END. Lo nico nuevo en este programa est en la lnea 15, en la instruccin if. Como vemos, en la lnea nmero 9 el usuario ingresa un nmero entero que corresponder a su edad. En la lnea 15 decimos si edad es mayor a 50 entonces. La condicin edad>50 es un booleano que valdr true si edad resulta ser mayor a 50 o false en caso contrario. La lnea 16 se ejecutar solo si se cumple la condicin, si no ser salteada completamente. Es posible colocar expresiones matemticas dentro de las condiciones. Ahora veamos un ejemplo con el mismo programa pero que existan dos caminos posibles a tomar. Si el usuario tiene ms de 50 aos le diremos viejo y si no le diremos que es joven:

1 PROGRAM viejo; 2 3 Var 4 edad: integer; //Variable para guardar la edad. 5 6 BEGIN 7 //Mostramos mensaje y leemos la edad. 8 write('Ingrese su edad: '); 9 readln(edad); 10 11 //Mostramos lo mismo que ya ingres. 12 writeln('Usted tiene ',edad,' aos.'); 13 14 //Si tiene ms de 50 aos le decimos viejo. 15 If edad>50 then 16 writeln('Usted es un viejo') 17 else 18 Writeln(Usted es joven); 19 20 END.

Vladimir Rodrguez

29

Programacin estructurada en Pascal


Este programa es esencialmente igual al anterior con la excepcin del else en la instruccin if. Esto significa que si se cumple la condicin se realizar la primera instruccin (la que est antes del else) y en caso contrario se ejecutar lo que est luego del else. Vean que luego de que escribimos ifthen la siguiente lnea est corrida unas columnas hacia la derecha, o sea tiene ms sangra que todo lo dems. Esto es lo que, como ya dije, llamamos indentacin. Es para dejar el cdigo ms legible, de este modo se entiende bien que la instruccin de la lnea 16 corresponde al IF y la de la lnea 18 corresponde al else. Notar que la instruccin de la lnea 16 no termina en punto y coma. Esto se debe a que si as fuera estaramos quebrando el If, o sea, estaramos diciendo que hasta ah llega esa instruccin y luego vendr otra por separado, pero sin embargo lo que viene es un else que es parte del if y por tanto corresponde a la misma sentencia. En todas las instrucciones del tipo ifthenelse nunca colocar un punto y coma antes del else. Anidacin de la instruccin Ifthen: Es posible colocar un if dentro de otro if. A esto se lo conoce como anidacin y se usa a muy menudo. Sin embargo hay que tener mucho cuidado de hacerlo bien o podra darse que nosotros creemos que el programa tomar cierto camino cuando en realidad no lo har. Veremos un ejemplo de eso luego del de a continuacin: Veamos un ejemplo en el que se nos pedir la edad dos veces. Si ingresamos una edad mayor a 50 y otra menor nos dir que somos viejos jvenes. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 PROGRAM anidacion; Var edad1, edad2: integer; BEGIN Write(Ingresa tu edad: ); Readln(edad1); Write(Ingresa tu edad nuevamente: ); Readln(edad2); If edad1>50 then If edad2<50 then Writeln(Eres un viejo joven); END.

Como vemos, nuestro programa nos pide el ingreso de nmeros enteros que corresponden a nuestra edad. En la lnea 12 decimos si el valor en edad1 es mayor a 50 entonces si el valor en edad2 es menor a 50 escribe Eres un viejo joven. Anidacin de un ifthen con un ifthenelse: Es posible hacer todas las anidaciones que se quieran, sin embargo como ya dije antes, debemos tener cuidado. Aqu dar un ejemplo de una anidacin que nosotros podramos interpretar de forma errnea. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 PROGRAM anidacion2; Var edad1, edad2: integer; BEGIN Write(Ingresa tu edad: ); Readln(edad1); Write(Ingresa nuevamente tu edad: ); Readln(edad2); If edad1>50 then If edad1=edad2 then Writeln(Eres un viejo)

Vladimir Rodrguez

30

Programacin estructurada en Pascal


15 16 17 18 else Writeln(Eres joven); END.

En este ejemplo uno podra interpretar que si tenemos ms de 50 aos y adems ingresamos las dos veces la misma edad aparecer el mensaje Eres un viejo, y si edad1 era menor a 50 nos aparecer el mensaje Eres joven. Sin embargo no es as, esa instruccin se fijar si nuestra edad es mayor a 50 y solo si eso es cierto luego ver si ambas edades eran iguales, si es as aparecer el mensaje Eres un viejo y si no aparecer el mensaje Eres joven. La correcta indentacin de esa instruccin es la siguiente: If edad1>50 then If edad1=edad2 then Wirteln(Eres un viejo) else Writeln(Eres un joven); Como ven, solo se ejecutar esto si edad1>50 resulta ser true. La forma correcta de escribir esta instruccin para obtener el resultado que interpretbamos anteriormente sera: If edad1>50 then begin If edad1=edad2 then Wirteln(Eres un viejo); end else Writeln(Eres un joven); Como ven, hemos encerrado entre begin y end la segunda instruccin if. Esto hace que todo lo que est dentro del rea abarcada por esas dos palabras sea como una sola instruccin para el programa, a pesar de que all dentro podemos poner todas las que queramos. De no hacer esto, el else formara parte del segundo if y no del primero. Debemos recordar que un else cierra siempre al if que se encuentre ms prximo a l. Para quebrar esto debemos usar begin y end. Los delimitantes begin y end se usan para indicar que al tomar cierto flujo de ejecucin dada una condicin el programa debe efectuar muchas instrucciones. No servira de mucho que por cada if que usemos solo podamos dictar una instruccin. La sintaxis genrica sera la siguiente: If condicion then begin Instruccion1; Instruccion2; . . . InstruccionN; end else begin Instruccion1; Instruccion2; . . . InstruccionN; end; Vean que tambin es posible usar los delimitantes begin y end para la instruccin else del if. Estos begin y end forman lo que llamamos bloques de instrucciones y difieren del begin y end principales ya que estos forman un nico bloque que es el programa completo. Luego de un end va enseguida un punto y coma que indica el final del bloque y no un punto como en el caso del end principal. Notar que el end anterior al else no finaliza con punto y coma. Esto se debe a lo que ya expliqu antes. Recordar que nunca, antes de una instruccin else que forma parte de un if debe ir colocado un punto y coma.

Vladimir Rodrguez

31

Programacin estructurada en Pascal


Condiciones compuestas: Hasta ahora hemos visto como dada una condicin especfica el programa tomar un camino u otro para realizar sus tareas. Sin embargo normalmente deben cumplirse varias condiciones para que un programa tome un camino u otro. Aqu entramos a componer condiciones, o sea, a decir cosas como: Si pasa tal cosa y tal otra has esta tarea o si pasa tal otra cosa has esta. Aprenderemos a usar los operadores booleanos para componer condiciones. Veamos un ejemplo parecido al anterior: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 PROGRAM anidacion2; Var edad1, edad2: integer; BEGIN Write(Ingresa tu edad: ); Readln(edad1); Write(Ingresa nuevamente tu edad: ); Readln(edad2); If (edad1>50) and (edad1=edad2) then Writeln(Eres un viejo) else Writeln(O eres joven o mentiroso); END.

Aqu vemos que en la instruccin IF hay dos condiciones entre parntesis unidas por la palabra reservada AND. Esto significa que se ejecutar la instruccin del IF si ambas condiciones son verdaderas, o sea, si se cumple a la vez que edad1>50 y que edad1=edad2. Basta con que una de ellas sea falsa para que no se ejecute la instruccin del IF y se pase a la del ELSE. En ese caso no sabremos si sucedi porque el usuario era joven o si era un mentiroso que ingres dos edades diferentes. Estas composiciones son evaluadas por Free Pascal con el mtodo conocido como circuito corto. Esto es que, si la primera condicin del AND es falsa, ya no se evaluar la segunda porque aunque esta fuera verdadera la condicin total resulta falsa. As nacen las tablas de verdad. AND en ingls significa Y. Si nosotros quisiramos haber dicho que se ejecute el IF si la primera condicin la otra eran verdaderas deberamos haber usado el operador OR. Este es verdadero si al menos una de las condiciones es verdadera. Tambin se evala por circuito corto, o sea, si la primera condicin es verdadera ya no se evaluar la segunda porque aunque resulte falsa la condicin total OR ser verdadera. Tablas de verdad: AND Expresin1 TRUE TRUE FALSE FALSE Expresin2 TRUE FALSE TRUE FALSE OR Expresin1 TRUE TRUE FALSE FALSE Expresin2 TRUE FALSE TRUE FALSE Expresin1 OR Expresin2 TRUE TRUE TRUE FALSE Expresin1 AND Expresin2 TRUE FALSE FALSE FALSE

Existe tambin el operador booleano NOT que niega una condicin, o sea, da el valor opuesto a esta. En principio uno se pregunta para que servira algo como eso. Ms adelante cuando comencemos a trabajar con la variables boolean veremos el uso de este operador. Veamos su tabla: NOT Expresin NOT Expresin TURE FALSE FALSE TRUE

Vladimir Rodrguez

32

Programacin estructurada en Pascal


Operadores relacionales: Son los que comparan dos expresiones: Operador = > < >= <= <> Expresin comparativa A=B A>B A<B A >= B A <= B A <> B Significado A es igual a B A es mayor que B A es menor que B A es mayor o igual a B A es menor o igual a B A es distinto de B

Un ejemplo matemtico: Bien. Haremos un programa en el cual aplicaremos casi todo lo dado hasta ahora. Se nos pide realizar un programa que calcule las races de polinomios de segundo grado cuyos coeficientes sern ingresados por el usuario, y muestre en pantalla los mensajes correspondientes. Por si alguno de ustedes no est bien familiarizado con polinomios explicar brevemente lo que es uno de segundo grado. Un polinomio es una funcin matemtica con una nica incgnita X la cual est elevada a distintos exponentes en los diferentes trminos de la ecuacin. Para que se vea mejor, un polinomio de segundo grado tiene la forma aX2 + bX + c donde a, b y c son nmeros reales. Por ejemplo, un polinomio podra ser 2X2 + 4X + 2. Los nmeros que acompaan a las X (a, b y c) son llamados coeficientes. Las races de un polinomio son aquellos valores de X que hacen que la ecuacin sea nula, o sea, que valga 0. En el ejemplo que tenemos all, una raz de ese polinomio es -1. Si cambiamos la incgnita X por -1 efectivamente vemos que todo se anula: 2*(-1)2 + 4*(-1) + 2 = 2*1 4 + 2 = 2 4 + 2= -2 + 2 = 0. Dado un polinomio de segundo grado puede suceder que tenga dos races diferentes, una nica raz (llamada raz doble) o que no tenga raz. Para hallar las races de un polinomio aX2 + bX + c se usa la conocida frmula de Bascaras:

-b(b2-4*a*c) 2*a
El trmino bajo la raz cuadrada (b2-4*a*c) es llamado discriminante ya que de l depende si el polinomio tiene dos races, una sola o no tiene. Si el discriminante es mayor que 0 efectivamente tendremos dos races distintas ya que por la forma de la frmula tenemos un que divide la frmula en dos partes, por un lado resolvemos la ecuacin con el signo de + luego de b, y luego resolvemos la frmula con el signo de luego del b:

-b+(b2-4*a*c) 2*a

-b-(b2-4*a*c) 2*a

Esto dar dos resultados diferentes, cada uno correspondiendo a una raz. Si el discriminante es nulo, o sea igual a 0, la raz cuadrada de 0 es igual a 0, por tanto sera estpido separar en dos la ecuacin ya que hacer b+0 o b-0 da exactamente igual, por lo cual el resultado ser nico. En este caso tenemos una nica raz doble. Si el discriminante es menor que 0 no podremos hallar su raz cuadrada ya que no existe raz de un nmero negativo. En este caso la frmula no puede resolverse y decimos que no existen races reales. En este caso pueden hallarse races complejas, pero eso no lo haremos ahora ya que tiene sentido solo para aquellos que se lleven bien con las matemticas.

Muy bien, teniendo cierto conocimiento sobre el problema comencemos a plantearnos como lo resolveremos para programarlo. El usuario ingresar en la entrada estndar los coeficientes a, b y c de nuestro polinomio. Teniendo esos valores primero debemos verificar que el valor a sea distinto de 0 ya que de ser as no estaramos enfrentndonos a un polinomio de segundo grado sino a uno de grado uno o cero. Luego deberemos evaluar el discriminante y segn lo que este de cmo resultado tomaremos tres caminos distintos para mostrar los resultados al usuario.

Vladimir Rodrguez

33

Programacin estructurada en Pascal


1 PROGRAM polinomio; 2 3 Var 4 a, b, c: real; //Los coeficientes del polinomio. 5 discriminante: real; //El discriminante. 6 raiz1, raiz2: real; //Las races del polinomio. 7 8 BEGIN 9 //Pedimos al usuario el ingreso de datos y leemos los mismos. 10 write('Ingrese los coeficientes separados por espacio: '); 11 readln(a,b,c); 12 13 //Verificamos que el coeficiente a sea no nulo. 14 If a=0 then 15 writeln('Usted no ha ingresado un polinomio de segundo grado.') 16 else 17 begin 18 //Calculamos el discriminante. 19 discriminante:= sqr(b)-4*a*c; 20 21 //Tomaremos los tres caminos segn el valor discriminante. 22 If discriminante=0 then 23 begin 24 //El polinomio tiene una nica raz. 25 raiz1:= -b/(2*a); 26 writeln('El polinomio tiene una raz doble: ',raiz1:2:2); 27 end 28 else 29 If discriminante>0 then 30 begin 31 //El polinomio tiene dos races. 32 raiz1:=(-b+sqrt(discriminante))/(2*a); 33 raiz2:=(-b-sqrt(discriminante))/(2*a); 34 35 writeln('El polinomio tiene dos races reales: ',raiz1:2:2,' y ',raiz2:2:2); 36 end 37 else 38 writeln('No existen races reales.'); 39 end; //Fin de la instruccin ELSE del IF principal. 40 END. Muy bien, como primera cosa les dir que a pesar de la explicacin que yo pueda dar aqu ser conveniente que ustedes mismos estudien este programa para comprenderlo bien. No es para nada complicado pero puede resultar confuso gracias a las anidaciones que se han hecho de las funciones IFTHENELSE. En las lneas 4, 5 y 6 declaramos todas las variables necesarias para que nuestro programa funcione correctamente. En la lnea nmero 11 leemos los tres coeficientes a la vez. Luego tenemos un IFTHENELSE principal que, si el coeficiente a es igual a cero mostrar un mensaje de error al usuario y solo en caso contrario pasar a realizar todas las dems tareas en su instruccin else. En ese caso calculamos primero el discriminante ya que de l dependern los caminos a tomar. Observar que al hacerlo (en la lnea 19) usamos la funcin sqr que calcula el cuadrado de un nmero. En vez de eso podramos haber puesto b*b que es lo mismo. Si el discriminante es igual a 0 mostraremos al usuario la raz doble, sino, si el discriminante es mayor que 0 calculamos y mostramos ambas races, y en caso contrario le diremos al usuario que no existen races reales. Es importante que entiendan el uso de los begin y end en este programa. Recuerden que estos delimitan bloques de programa los cuales son vistos como una nica instruccin. Si escribiera el cdigo anterior a partir del primer IF de modo que en cada sentencia tuviramos una nica instruccin quedara as: If condicion1 then Instruccion1 Else Begin //Aqu debera estar el clculo del discriminante. If condicion2 then Instruccion2 Else

Vladimir Rodrguez

34

Programacin estructurada en Pascal


If condicion3 then Instruccion3 Else Instruccion4; End; Esto, si tomramos todo lo que est entre el BEGIN y el END que vemos all como una nica instruccin quedara simplemente como If condicion1 then Instruccion1 Else Instruccion2; donde la Instruccion2 sera todo el enorme bloque entre el BEGIN y END.

Vladimir Rodrguez

35

Programacin estructurada en Pascal Instruccin de seleccin CASEELSE:


La instruccin CASE que veremos a continuacin podra considerarse como la forma correcta de escribir una enorme cantidad de IF anidados. Veamos primero un ejemplo anidando IF en el cual el programa despliega al usuario varias opciones y dependiendo de lo que ste seleccione ser lo que har: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 PROGRAM menu; Var opcion: char; numero: integer; BEGIN writeln('1--> writeln('2--> writeln('3--> Muestra un mensaje en pantalla'); Ingresar un nmero'); Ingresar un caracter');

write('Ingrese una opcion y presione ENTER: '); readln(opcion); writeln; If opcion='1' then writeln('MENSAJE DESPLEGADO') else if opcion='2' then begin write('Ingrese un nmero entero: '); readln(numero); writeln('Ha ingresado ',numero,'.'); end else if opcion='3' then begin write('Ingrese un caracter: '); readln(opcion); writeln('Ha ingresado ',opcion); end else writeln('ERROR. No existe la opcin ',opcion); END.

En este ejemplo trabajaremos por primera vez con una variable del tipo char, o sea que contendr caracteres, no una cadena como el tipo string sino uno solo. Esto es por un simple motivo. Al ser del tipo char cualquier smbolo que ingresemos ser ledo sin problemas. Nosotros mostramos las opciones del men con nmeros, entonces uno podra decir que para leer la opcin que el usuario ingrese podramos haber declarado una variable integer o real, sin embargo de hacerlo as, si el usuario en vez de ingresar un nmero ingresa una letra el programa dar un error en tiempo de ejecucin al intentar almacenar una letra en una variable numrica y se cerrar. Sin embargo, al ser del tipo char, si el usuario ingresa una letra esta se leer sin problemas y podremos desplegar al usuario un mensaje de error que indique que ha seleccionado una opcin incorrecta, y de ser posible pedirle que lo intente de nuevo. Notar como en las condiciones de los IF comparamos el carcter ledo en la variable opcion con un carcter escribiendo este entre comillas simples. Es importante saber que si el usuario ingresa un 1 en su entrada, nosotros leeremos el carcter 1 y NO el nmero 1. El carcter 1 es como una letra o un smbolo, no es un nmero que se puede sumar o restar, es un smbolo. Del mismo modo que uno no puede sumar letras, a+b por ejemplo, no se pueden sumar caracteres numricos. No es lo mismo 1 que 1. El primero es un nmero y el otro un carcter. 1+2 equivale a la cadena 12, y 1+2 es igual a 3. Esta diferencia resulta esencial, es importante que lo comprendan. No he puesto comentarios en este programa apropsito para que ustedes lo lean y entiendan por s solos. Bsicamente decimos, si el usuario ingresa el 1 muestra un mensaje, sino, si el usuario ingresa el 2 pide que ingrese un numero y mustraselo, sino, si el usuario ingresa el 3 pdele que ingrese un carcter y mustraselo, sino dile que lo que ha ingresado no es una opcin correcta.

Vladimir Rodrguez

36

Programacin estructurada en Pascal


Ahora veamos el mismo programa usando la instruccin CASE: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 PROGRAM menu; Var opcion: char; numero: integer; BEGIN writeln('1--> writeln('2--> writeln('3--> Muestra un mensaje en pantalla'); Ingresar un nmero'); Ingresar un caracter');

write('Ingrese una opcion y presione ENTER: '); readln(opcion); writeln; Case opcion of '1': writeln('MENSAJE DESPLEGADO'); '2': begin write('Ingrese un nmero entero: '); readln(numero); writeln('Ha ingresado ',numero,'.'); end; '3': begin write('Ingrese un caracter: '); readln(opcion); writeln('Ha ingresado ',opcion); end; else writeln('ERROR. No existe la opcin ',opcion); end; //De la instruccin CASE. END.

Hasta la lnea 16 nuestros ejemplos son exactamente iguales. Ahora, en la lnea 17 en vez de tener un IF tenemos la declaracin de la instruccin CASE. Su sintaxis es la siguiente: Case variable of Etiqueta1: instruccion1; Etiqueta2: instruccion2; ... EtiquetaN: instruccinN; Else Intruccion_por_defecto; End; Esta instruccin se fijar en el valor de la variable colocada entre la palabra CASE y la palabra OF, en nuestro ejemplo se trata de la variable opcion. Luego tomar el camino en el cual el valor de la variable sea igual al de la etiqueta. El ELSE al final indica lo que se debe hacer si la variable no corresponde con ninguna de las etiquetas anteriores. Este ELSE puede ir o no. Si no est no se ejecutar nada y se continuar con lo que haya debajo en el cdigo, pero no habr error. En este caso hemos usado el ELSE par decir al usuario que no ingres nada de lo esperado. Notar que antes de este ELSE s debe ir un punto y coma que cierre la instruccin anterior, no como en el caso de los ELSE que se usan en una instruccin IF. Siempre al final de la instruccin CASE debe ir un END que finalice en punto y coma para indicar el final de esta instruccin. No colocarlo es un error de sintaxis. Notar que las instrucciones para cada etiqueta pueden ser bloques de instrucciones delimitados por sus respectivos BEGIN y END. Es importante saber que las etiquetas representan los valores que debe tomar la variable del encabezado del CASE para que el programa tome tal o cual camino. Es posible indicar ms de un valor a la vez en una misma etiqueta, simplemente separando cada valor por una coma: Case variable of Valor1, valor2: instruccion1; Valor3, valor4, valor5: instruccion2; . . . ValorI, valorN: instruccionJ;

Vladimir Rodrguez

37

Programacin estructurada en Pascal


IMPORTANTE: La variable del encabezado del CASE debe ser de un tipo ORDINAL, o sea integer, char, enumerado, boolean o subrango. Ejercicio: Este es un simple ejercicio para que usen CASE. Quiero que en un solo programa junten los siguientes ejemplos que vimos hasta ahora: el programa HolaMundo de la pgina 11, el del rea de un Tringulo de la pgina 15, el que divida dos cifras de la pgina 18 habindolo modificado para que muestre un error si se ingresa la segunda cifra igual a 0, y el programa que desglosaba un nmero de cuatro cifras de la pgina 22 modificado para que muestre un error si el usuario ingresa un nmero invlido, o sea, uno que sea menor a 1000 o mayor a 9999. Su programa debe mostrar un men como el siguiente: 1) 2) 3) 4) Hola Mundo Calcular el rea de un Tringulo Dividir dos nmeros reales Sumar los dgitos de un nmero de cuatro cifras

Seleccin: Cuando el usuario elija una opcin su programa habr de realizar las tareas pertinentes y en caso contrario notificar el error. No continen hasta no lograr hacer esto.

Vladimir Rodrguez

38

Programacin estructurada en Pascal Secuencia de repeticin FOR:


Adems seleccionar distintos caminos dadas ciertas condiciones, muchas veces hace falta repetir ciertas tareas segn otras condiciones. Por ejemplo, en nuestro programa de polinomios de segundo grado sera conveniente que si el usuario ingresa el coeficiente a nulo, adems de mostrar el mensaje de error, el programa vuelva a pedir que se ingresen los coeficientes, o si en nuestro programa de la instruccin CASE, el usuario ingresara una opcin que no est en el men adems de notificrselo sera correcto volver a pedir que ingrese una. Existen tres estructuras de repeticin; la que vamos a ver a continuacin llamada FOR, y otras dos que veremos luego llamadas WHILEDO y REPEATUNTIL. FOR (que en ingls significa PARA o POR) repite una tarea una cantidad especfica de veces, ni mas ni menos. Su sintaxis es la siguiente: For variable:= valor_inicial to valor_final do Instruccin; Por ejemplo, si quisiramos imprimir la letra A unas 10 veces la declaracin del FOR sera algo as: For i:=1 to 10 do Write(A); En este caso veramos una salida como esta: AAAAAAAAAA La variable en el encabezado del FOR debe ser declara junto con todas las variables del programa. Esta variable es conocida como variable de control del FOR y debe ser de un tipo ordinal. De ms est decir que el valor final debe ser del mismo tipo que el inicial (por ejemplo puede ser for i:= a to z do). Su valor es inicializado con el valor_inicial del encabezado del FOR. La variable de control comienza valiendo 1, el programa imprime una A, luego la variable aumenta su valor a 2 y se imprime la segunda A. As hasta que la variable alcanza el valor final. Esto es muy importante ya que es lo ms comn usar la variable de control del FOR dentro de las instrucciones que este realiza. Debo aadir que si el FOR ha de realizar ms de una instruccin en su ejecucin debemos encerrar estas entre un BEGIN y un END. Resulta obvio que FOR, TO y DO son palabras reservadas de Pascal. Veamos un ejemplo en el cual usamos la variable de control del FOR. Imprimiremos en pantalla los 10 primeros nmero pares a partir del 0 sin incluir a este: 1 PROGRAM pares; 2 3 Var 4 i: integer; 5 6 BEGIN 7 write('Los 10 primeros pares son: '); 8 9 For i:=1 to 20 do 10 If i mod 2= 0 then 11 write(i,' '); 12 END. En la lnea 7 mostramos al usuario un mensaje. En la novena lnea comienza la declaracin del FOR donde inicializamos i en 1 y continuaremos hasta que valga 20. El IF en la lnea 10 se encarga de ver si el valor actual de i es par, o sea si el resto de dividirlo entre 2 es igual a 0. En ese caso imprimimos su valor y un espacio, sino no hacemos nada y esperamos la siguiente iteracin. Al proceso de repetir varias veces un mismo segmento de cdigo se lo llama iteracin. Nuestro FOR iterar 20 veces. Es importante jams modificar la variable de control mientras se est ejecutando el FOR, o sea, no hacer por ejemplo i:= 10 dentro del FOR ya que eso produce errores muy inesperados y dependen mucho del compilador usado para crear el programa. Puede usarse el valor de la variable de control para todo lo que se necesite, incluso incluirlo en expresiones y condiciones, pero nunca modificarlo. Ahora veamos el mismo programa, pero solo que esta vez le pediremos al usuario que ingrese cuantos nmeros pares quiere visualizar: 1 2 3 4 6 7 8 PROGRAM PrimerosPares; Var i, pares: integer; BEGIN write('Cuantos pares quieres visualizar? ');

Vladimir Rodrguez

39

Programacin estructurada en Pascal


9 readln(pares); 10 11 writeln; 12 write('Los primeros ',pares,' pares son: '); 13 14 pares:= pares*2; 15 16 For i:=1 to pares do 17 If i mod 2= 0 then 18 write(i,' '); 19 END. En la lnea 8 mostramos el mensaje al usuario para, en la siguiente lnea, pedirle que ingrese cuntos pares desea ver. En la lnea 11 usamos el procedimiento writeln sin parmetros para que imprima una lnea en blanco. En la lnea 12 mostramos un mensaje al usuario. En la lnea 14 hay algo nuevo. A la variable pares le asignamos su valor anterior multiplicado por 2 ya que si el usuario desea ver, por ejemplo, los diez primeros pares nosotros deberamos iterar del 1 al 20. Esto de asignar a una variable un valor que depende de su valor anterior es muy comn en la programacin. A dichas variables se las conoce como acumuladores. Esto lo veremos en ms detalle cuando trabajemos con WHILE y REPEAT. En la lnea 16 cambiamos el valor final del encabezado del FOR por la variable pares. Esto es lo ms comn en el uso de esta instruccin. No hace falta indicar un valor nosotros mismos, sino que podemos colocar nombres de variables, constantes o incluso expresiones matemticas siempre y cuando el tipo de la variable de control y el del valor final sean el mismo y estos sean ordinales.

Anidacin del FOR: Veamos un ejemplo donde el usuario ingresar un nmero que indicar el largo del lado de un cuadrado y dibujaremos este con el carcter *: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 PROGRAM Cuadrado; Const caracter= '*'; Var i, j, lado: integer; BEGIN write('Ingresa el largo del lado: '); readln(lado); writeln; For i:=1 to lado do begin For j:=1 to lado do write(caracter); writeln; end; END.

Lo interesante en este programa es analizar lo que sucede desde la lnea 15 en adelante. Tenemos dos FOR, uno dentro de otro. Lo primero a resaltar es el uso de dos variables de control diferentes, una para cada FOR. Si usramos la misma variable para ambos uno modificara la del otro y se ocasionara un caos. Si quieren prueben este programa as como est y luego con la misma variable de control. Es probable que el compilador los regae por eso y se produzca un error en tiempo de compilacin. Veamos, cuando i vale 1 entramos al FOR principal. All tenemos otro FOR el cual se ejecutar hasta el final antes de volver al primer FOR. Cuando j vale 1 imprimimos un * (est definido en la constante caracter). Luego j vale 2 y se imprime un segundo * en la misma lnea ya que estamos usando un procedimiento write. As continuamos hasta que se imprimen tantos * en una lnea como lo indique la variable largo. Ahora pasamos a la lnea 20 del programa donde est writeln para escribir una lnea en blanco, o sea, para bajar un rengln. Ahora i vale 2. Volvemos a entrar en el FOR principal y el FOR de dentro vuelve a comenzar con j en 1. Imprime los *, se baja un rengln y as hasta que i sea igual al valor de la variable lado.

Vladimir Rodrguez

40

Programacin estructurada en Pascal


Notar que la instruccin writeln de la lnea 20 est dentro del FOR principal pero no forma parte del FOR interno. Otra forma del FOR es la siguiente: For variable:=valor_inicial downto valor_final do Instruccin;

Esto funciona exactamente igual a la forma anterior del FOR con la diferencia de que valor_inicial es mayor que valor_final. O sea que la variable de control ir decreciendo en vez de aumentar. Por ejemplo: For i:=20 downto 1 do Instruccion; En este caso i comenzar valiendo 20, luego 19, luego 18, y as hasta llegar al 1. NOTAS: Nunca asuman el valor que tendr la variable de control una vez finalizado el FOR. En este ejemplo de FOR que va de 20 a 1 uno podra decir que i vale 1 al final, pero esto puede no ser as y depende del compilador. Si van a volver a usar esta variable debern inicializarla ustedes mismos con el valor apropiado. A continuacin les planteo una serie de ejercicios de aplicacin del FOR y algunos temas ya vistos. Por favor, no continen si no son capaces de resolver estos ejercicios. Si realmente se trancan con alguno envenme un e-mail a mstrvladi@hotmail.com explicndome cual ejercicio les est dando problemas y les ayudar o les enviar la solucin. Ejercicio 1: Determinen cules de los siguientes fragmentos de cdigo producen la misma salida: a) FOR i:=1 TO 3 DO FOR j:= i+1 TO 3 DO write(i,j) b) FOR i:=1 TO 3 DO write (i, i+1) c) FOR i:=1 TO 4 DO IF (i=1) OR (i=4) THEN write(i) ELSE write(i,i)

Ejercicio 2: Escriban un programa que lea desde el teclado un valor entero n. A continuacin, el programa deber leer n enteros y luego desplegar el mayor y el menor de ellos. Ejemplo de entrada: n=8 Ingrese 8 enteros: 5 12 36 4 21 95 12 18 Ejemplo de salida: El mayor entero ingresado es: 95 El menor entero ingresado es: 4

Vladimir Rodrguez

41

Programacin estructurada en Pascal


Ejercicio 3: Escriban un programa que lea de la entrada estndar 5 valores positivos, todos menores que 60 y produzca una grfica de barras horizontales similar a la que se muestra en el ejemplo para estos datos: Ejemplo de entrada: Ingrese 5 valores: 5 12 17 35 8 Ejemplo de salida: ***** ************ ***************** *********************************** ********

Ejercicio 4: Escriban un programa que lea de la entrada estndar un carcter c y un entero n. El programa debe desplegar un tringulo de n lneas formado por el carcter c segn se muestra en el siguiente ejemplo: Ejemplo de entrada: n=8 c=$ Ejemplo de salida: $$$$$$$$ $$$$$$$ $$$$$$ $$$$$ $$$$ $$$ $$ $

Vladimir Rodrguez

42

Programacin estructurada en Pascal DEBUGER


Antes de continuar quiero que aprendan a usar el DEBUGER (depurador) de Free Pascal para que puedan testear sus programas cuando tengan problemas con ellos. Primero que nada necesitarn ver la ventana watches que es la que les mostrar los valores que tomen sus variables. Para acceder a ella vallan al men Debug Watches. Debern disminuir el tamao de la ventana de su cdigo para poder ver ambas a la vez. Para ello seleccinenla para que quede activa y presionen Ctrl+F5, el borde quedar verde. Pueden moverla con las flechas de direccin y cambiar su tamao manteniendo presionada Shift cuando presionen una flecha. Cuando hayan ajustado el tamao a uno que les sirva deben agregar a la ventana WATCHES las variables que necesitan ver. Para ello vallan al men Debug Add watch o presionen Ctrl+F7. En el cuadro de dilogo ingresen el nombre de la variable a observar y esta aparecer en la ventana WATCHES. Agreguen tantas variables como quieran. Ahora deben ejecutar su programa paso a paso. Para ello, una vez compilado, vallan al men RUN y elijan STEP OVER. Ahora su programa comenzar pero estar detenido. Presionen F7 o F8 para avanzar una lnea. El programa solo avanzar al presionar una de estas teclas. La diferencia entre una y otra es que F8 no entrar en los procedimientos y funciones (lo veremos luego) y F7 si lo har. Cada vez que avancen vern como se modifican sus variables. Tambin pueden ir viendo la pantalla de salida mientras usan el debuger, para ello vayan al men Debug Output y les aparecer la salida. Debern ajustar el tamao de cada ventana para que puedan ver todas a la vez.

Vladimir Rodrguez

43

Programacin estructurada en Pascal Secuencia de repeticin WHILEDO:


Hemos visto la repeticin FOR que se ejecutaba una cierta cantidad de veces estipulada, ni ms ni menos. Sin embargo, aunque FOR resulta muy til para muchas tareas, hay cosas que necesitan una repeticin que est controlada por una o ms condiciones. Por ejemplo, imaginen un programa que pide un cdigo de entrada a un usuario. El usuario tiene 5 intentos posibles para introducir el cdigo correcto. Si el usuario se equivoca el programa le notifica el error, indica cuantos intentos le quedan y le vuelve a pedir el cdigo. Si el usuario acierta antes de que se le acaben los intentos el programa ya no le pedir el cdigo y continuar su curso. Si el usuario gast todos sus intentos sin adivinar el programa se cerrar. Aqu tenemos una repeticin que puede detenerse por dos cosas, que el usuario acierte el cdigo o que gaste sus intentos. Es imposible saber en qu intento el usuario acertar el cdigo por lo cual una instruccin FOR no servira. Veremos este ejemplo utilizando la secuencia WHILEDO (MIENTRASHAS). Veamos antes que nada su sintaxis: While condicion do Instruccin; Esto significa, mientras se cumpla la condicin ejecuta tu instruccin. Una vez hecha la instruccin, while regresar a su encabezado y volver a verificar la condicin. Si esta sigue siendo verdadera volver a ejecutarse. En caso contrario saltear la instruccin y el programa continuar su curso. No est de ms decir que la condicin puede ser compuesta y que la instruccin puede ser un bloque de instrucciones delimitado por BEGIN y END. Veamos el ejemplo del cdigo a adivinar: 1 PROGRAM codigo; 2 3 Const 4 max_intentos= 5; 5 codigo_secreto= 107; 6 7 Var 8 codigo_ingresado, intento: integer; 9 adivino, perdio: boolean; 10 11 BEGIN 12 //Inicializamos los booleanos en false. 13 adivino:= false; 14 perdio:= false; 15 16 intento:=0; //Todava no ha intentado adivinar. 17 18 While (not adivino) and (not perdio) do 19 begin 20 writeln('Intentos restantes: ',max_intentos-intento); 21 22 intento:= intento+1; //Aumentamos 1 al intento actual. 23 24 write('INGRESE CDIGO DE ACCESO: '); 25 readln(codigo_ingresado); //Leemos el cdigo. 26 27 If codigo_ingresado=codigo_secreto then 28 adivino:= true 29 else 30 writeln('ERROR. CDIGO INCORRECTO.'); 31 32 writeln; 33 34 If (not adivino) and (intento=max_intentos) then 35 perdio:= true; 36 37 end; //Del WHILE. 38 39 If adivino then 40 writeln('Felicidades. Adivin.') 41 else 42 writeln('No acert el cdigo en ',max_intentos,' intentos.'); 43 44 END.

Vladimir Rodrguez

44

Programacin estructurada en Pascal


Definimos para este programa, dos constantes, una llamada max_intentos que contiene la cantidad mxima de intentos que el usuario tiene para adivinar el cdigo y otra llamada codigo_secreto que contiene el valor numrico que el usuario debe adivinar. Luego declaramos las variables codigo_ingresado que ser la que guardar el valor que el usuario ingrese y otra llamada intento que dir la cantidad de veces que el usuario ha intentado adivinar hasta el momento. En este ejemplo vemos por primera vez uno de los usos de las variables booblean. En este caso declar dos, una llamada adivino que indicar el momento en el cual el usuario adivine el cdigo, y otra llamada perdio que indicar si el usuario ha gastado todos sus intentos sin adivinar el cdigo. Comenzamos inicializando ambos booleanos con el valor false ya que el usuario ni ha adivinado ni ha perdido. Tambin inicializamos la variable intento con el valor 0 ya que el usuario an no ha comenzado. Es importante siempre inicializar las variables con los valores apropiados y no asumir que ya lo tienen. Es comn que uno suponga que el valor de intento sea 0 ya que no se le asign nada hasta el momento, pero esto no es as, depende mucho del compilador que se use. Cuando uno declara una variable de algn tipo, esta puede tomar un valor cualquiera al azar que es desconocido por el usuario (basura). Hay compiladores que las inicializan con algn valor especfico. Sin embargo, al crear un software, nunca sabemos en el futuro cuando deberemos modificarlo o si debemos pasarle nuestro cdigo a algn otro programador para que l trabaje con este. Si la otra persona usa un compilador diferente entonces el programa probablemente no funcione como debe. SIEMPRE INICIALIZAR LAS VARIABLES!!! En la lnea 18 comienza el encabezado del WHILE cuyas instrucciones estarn en un bloque que va desde el BEGIN de la lnea 19 hasta el END de la lnea 37. Veamos el encabezado del WHILE ya que all las condiciones estn dadas por los booleanos. While (not adivino) and (not perdio) do es equivalente a decir While (adivino= false) and (perdio= false) do, o sea, estamos diciendo, Mientras adivino es falsa y perdio es falsa has (y all comienzan todas las instrucciones). Notar que la condicin es una condicin compuesta y que ser verdadera en tanto ambas condiciones comprendidas entre el operador AND sean verdaderas, o sea, cada condicin es verdadera si los booleanos son falsos. Esto es confuso, pero analcenlo por un minuto. Notros estamos preguntando adivino es falsa? Si es as la respuesta es SI, entonces pregunta perdio es falsa? Si esta respuesta tambin es SI la condicin es verdadera. La condicin, no las variables. Cuando uno est preguntado por el valor de un booleano no hace falta escribir esto como una comparacin. Fjense que el encabezado del WHILE no est escrito como la segunda alternativa que d, o sea, si uno quisiera decir WHILE (variable= true) DO solo debe escribir WHILE (variable) DO. Usar el nombre de un booleano en una condicin ya es preguntar por si es TRUE. Del mismo modo si uno quiere preguntar por si es FALSE, como en nuestro programa, debe anteponer el operador NOT antes del nombre del booleano. Bien, nuestro WHILE funcionar en tanto ambos booleanos sean FALSE, basta que uno no lo sea para que la condicin AND sea falsa y por tanto no se ejecute el WHILE. Como nosotros inicializamos ambos booleanos con FALSE sabemos que la primera vez que el programa llegue al WHILE su condicin ser verdadera y por tanto se ejecutar al menos una vez. Analicemos todo el bloque que compone al WHILE. Lo primero que hacemos es mostrar al usuario un mensaje que indica sus intentos restantes. Este nmero es restar el intento actual menos max_intentos. En la lnea 22 aumentamos en 1 el valor de intento ya que el usuario intentar adivinar. Esta es la idea de acumulador que nombr anteriormente. La instruccin intento:= intento+1 asigna a la variable intento su valor anterior ms uno. Si intento valiera 8 esa instruccin equivaldra a decir intento:= 8+1. Este es el procedimiento general para usar contadores, por ejemplo un programa que cuente la cantidad de palabras en un texto, los caracteres, etc. En las lneas 24 y 25 mostramos al usuario el mensaje que le indica que ingrese un cdigo y luego lo leemos. Este es ingresado como un entero. Si el usuario ingresa otros smbolos que no sean numricos nuestro programa se cerrar abruptamente. Ms adelante veremos como recibir una cadena de caracteres numricos y pasar estos a nmeros enteros o reales para lograr un verdadero control de errores por parte del usuario. Sin embargo eso no es pertinente en este momento y asumimos que siempre recibiremos un entero en la entrada estndar. En la lnea 27 usamos un IF para decir que si el cdigo ingresado por el usuario es igual al que deba adivinar, la variable booleana adivino cambie su valor a TRUE. Si esto sucediera, cuando el WHILE vuelva a su encabezado para evaluar la condicin esta ser falsa y ya no se ejecutar. En caso de que el usuario no adivine, el IF pasar a su instruccin ELSE en donde imprimimos un mensaje al usuario que le notifica de su error. Luego damos una instruccin de salto de lnea. En la lnea 34 tenemos una instruccin IF que en caso de que el usuario no haya adivinado el cdigo y haya alcanzado el mximo nmero de intentos cambiamos el valor de la variable perdio a TRUE. Fjense que el IF tiene una instruccin compuesta. Tal vez alguno de ustedes se pregunte por qu no simplemente cambias el valor de perdio a TRUE cuando el usuario haya alcanzado el nmero mximo de intentos? Entonces yo preguntara que pasara si el usuario adivina justo en el ltimo intento? An as se encendera la variable perdio aunque no haya perdido (llamo encender a que su valor sea TRUE). En ese caso perdio y adivino seran TRUE y eso estara mal. Aqu termina el bloque del WHILE y el programa volver a la lnea 18 para evaluar de nuevo la condicin de iteracin. Si esta es falsa entonces se saltear todo el bloque y pasar directo a la lnea 39, sino volver a entrar en el bloque del WHILE. Ya fuera del WHILE simplemente verificamos con un IF cul fue el motivo por el que salimos del WHILE y notificamos al usuario de ello.

Vladimir Rodrguez

45

Programacin estructurada en Pascal


El uso que dimos aqu de las variables booleanas es conocido como Banderas Booleanas ya que nuestras variables se encendern cuando se cumpla alguna condicin y nos avisarn algo. Sera como levantar una bandera para indicarle algo a alguien. El uso de banderas booleanas es muy comn aunque en principio uno no lo crea. A medida que la prctica en programar es mayor se comprende mejor a los booleanos y su uso aumenta. Yo en particular hago mucho uso de ellos, llegando incluso a abusarme un poco, cosa que no es aconsejable ya que el cdigo puede volverse confuso. Muy bien, ahora que ya conocen el uso de WHILE es hora de darle prctica. Quiero que modifiquen el programa del tringulo para que cuando el usuario ingrese base o altura con un valor nulo o negativo el programa le notifique su error y vuelva a pedrselo. Asuman que el usuario siempre ingresa nmeros reales en la entrada, no se preocupen todava por si ingresa otros caracteres. Tambin modifiquen el programa que efectuaba una divisin entre dos nmeros de modo que si el usuario ingresa el valor del cociente como 0 el programa se lo indique y vuelva a pedrselo. Hagan lo mismo con el programa que desglosaba un nmero de cuatro cifras. Si el usuario ingresa un nmero invlido vuelvan a pedrselo hasta que sea vlido. Un pequeo juego: Los tres ejercicios anteriores corresponden a modificar cdigos ya hechos por m y a remodificar lo que ya haban hecho en los ejercicios anteriores, que aunque no es del todo fcil es ms sencillo que disear un programa desde 0. Ahora les plantear un pequeo juego para que lo hagan. Podrn usar todo lo que hemos visto hasta el momento. Este juego se centrar en el uso del WHILE. El problema es el siguiente: Un jugador deber adivinar en un mximo de 15 intentos un nmero entre 1 y 100. Si el jugador adivina, el programa se lo notificar y terminar su ejecucin, en caso contrario el jugador recibir una pista para volver a intentar adivinar. El juego le dir si el nmero que debe adivinar es mayor o menor que el que ha ingresado y el jugador volver intentarlo. En cada caso el juego deber mostrar al jugador el nmero de intento actual y cuantos restantes le quedan. Cuando el usuario pierda, el programa deber mostrar cul era el nmero que deba adivinar. Siempre asumiremos que recibiremos un entero desde la entrada. El nmero a ser adivinado ser generado al azar por el juego (ya explicar esto a continuacin). Ejemplos de ejecucin: Ejemplo 1: Dispones de 15 intentos para adivinar. 1)--> 98 Muy bien!!! Has adivinado!!! Ejemplo 2: Dispones de 15 intentos para adivinar. 1)--> 99 Lo siento, no has acertado. El nmero que debes adivinar es menor. Dispones de 14 intentos para adivinar. 2)--> 80 Lo siento, no has acertado. El nmero que debes adivinar es mayor. Dispones de 13 intentos para adivinar. 3)--> 85 Muy bien!!! Has adivinado!!! Ejemplo 3: Dispones de 15 intentos para adivinar. 1)--> 60 Lo siento, no has acertado. El nmero que debes adivinar es menor. . . . Dispones de 1 intentos para adivinar. 15)--> 13 Lo siento, no has acertado. Lamentablemente has perdido. El nmero era 10.

Vladimir Rodrguez

46

Programacin estructurada en Pascal


Generar nmeros aleatorios: Para obtener un nmero al azar se utiliza la funcin random. Su sintaxis es la siguiente: Random(x) donde X es un entero que marca el nmero mximo que se puede generar. Random(x) devolver un nmero aleatorio entre 0 y X-1. Por ejemplo, si escribimos random(50) obtendremos un nmero al azar entre 0 y 49 inclusive. Veamos un ejemplo sencillo en el que el usuario ingresa cul es el tope y el programa le devolver un nmero aleatorio entre 1 y el nmero ingresado. Asumimos que el usuario ingresar un entero mayor que 1: 1 PROGRAM funcion_random; 2 3 Var 4 x, valor_aleatorio: integer; 5 6 BEGIN 7 randomize; 8 9 write('Ingrese un valor: '); 10 readln(x); 11 12 valor_aleatorio:= random(x) + 1; 14 writeln('El nmero obtenido entre 1 y ',x,' es: ',valor_aleatorio); 15 END. Bien, este programa es bien sencillo de entender. Tenemos dos variables, x y valor_aleatorio. La primera ser leda desde la entrada y guardar el valor ingresado por el usuario. La segunda guardar el nmero al azar obtenido por la funcin random. Lo primero a notar es que en la lnea 7 hacemos una llamada al procedimiento randomize. Este no lleva parmetro alguno, simplemente indica que luego en algn momento del programa ser utilizada la funcin random. Si no hacen esto no podrn usar esta funcin y tendrn un error en tiempo de compilacin. En la lnea 10 obtenemos el valor de X. En la lnea 12 asignamos a valor_aleatorio el valor obtenido por random(x) ms 1. Por qu ms 1? Si random(x) genera un nmero aleatorio entre 0 y X-1 pero nosotros queremos uno entre 1 y X solo basta sumar uno al resultado. Por ejemplo, si hiciramos random(10) podramos obtener los nmeros 0, 1, 2, 3, 4, 5, 6, 7, 8 o 9. Si quisiramos un nmero entre 1 y 10 basta sumar uno al valor sorteado. Si sale el 0, al sumar 1 obtenemos el 1. Si sale 9, al sumar 1 obtenemos el 10, o sea, corremos todo el intervalo un lugar a la derecha. Ahora s, ya deberan ser capaces de crear el juego del Adivinador. Toda duda que les surja deben envirmela a mstrvladi@hotmail.com .

NOTAS: En el ejemplo que trabajamos, nosotros usamos un IF para decidir si cambibamos el valor de un booleano a TRUE. Sin embargo no es necesario hacerlo as, la siguiente instruccin If codigo_ingresado=codigo_secreto then adivino:= true equivale a escribir adivino:= codigo_ingresado=codigo_secreto. De este modo estamos diciendo que adivino es true si se cumple la condicin codigo_ingresado=codigo_secreto. Si esto no es as el booleano ser FALSE. Esto es exactamente igual que la instruccin con IF.

Vladimir Rodrguez

47

Programacin estructurada en Pascal Secuencia de repeticin REPEATUNTIL:


Esta secuencia funciona de forma muy similar al WHILE, tanto as que algunos se preguntan cual es su verdadero propsito. Sin embargo a veces resultar til utilizar REPEAT y otras veces ser mejor utilizar WHILE. La sintaxis de esta instruccin es la siguiente: REPEAT Instrucciones; UNTIL condicion; Como primera diferencia notoria entre el WHILE y el REPEAT es que el primero verifica sus condiciones al inicio y el segundo lo hace al final. La instruccin REPEAT realizar todas las instrucciones comprendidas entre la palabra REPEAT y la palabra UNTIL, no hace falta colocar BEGIN y END para delimitar el bloque. Si tradujramos al espaol, esta funcin significa REPITEHASTA QUE a diferencia del WHILE que repeta mientras que una condicin fuera verdadera, REPEAT lo hace hasta que esa condicin sea verdadera, o sea, sigue iterando mientras su condicin es falsa, no como WHILE que lo haca mientras era verdadera. Como diferencia esencial, sabemos que REPEAT se ejecutar siempre al menos una vez ya que verificar su condicin de iteracin al final, no como WHILE que podra no ejecutarse nunca. Esto es lo que nos dice cuando conviene usar uno u otro. Si sabemos que nuestro bloque de cdigo siempre se ejecutar al menos una vez es conveniente usar un REPEAT en vez de un WHILE, sin embargo no es incorrecto hacerlo aunque s aconsejable. Centinela: Veremos ahora, aunque sin usar REPEAT un ejemplo de iteracin por centinela. Un centinela es un valor que tomar nuestra variable para indicar el fin de la iteracin, algo as como una bandera booleana, pero aplicado a otras variables. Vemoslo para comprenderlo mejor. El siguiente programa ir leyendo de la entrada estndar una serie de nmeros enteros positivos hasta que se ingrese un negativo. En ese caso ya no se leern ms nmeros y luego se mostrar la suma de todos los nmeros ingresados (excepto el negativo): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 PROGRAM centinela; Var numero, suma : integer; BEGIN (* lectura inicial *) ReadLn(numero); (* inicializacin *) suma:= 0; while numero > 0 do begin (* acumulacin *) suma:= suma + numero; (* siguiente lectura *) ReadLn(numero); end; (* mostrar resultado *) WriteLn('La suma de los nmeros es: ', suma); END.

Bien, en la lnea 8 leemos el primer valor que debemos sumar. En la lnea 10 inicializamos la variable suma con el valor 0 ya que an no ha sumado nada. En la lnea 13 comienza el WHILE solo si el nmero que ingresamos es mayor que 0, en caso contrario no se ejecutar. Aqu vemos por qu es mejor utilizar un WHILE que un REPEAT, ya que si el usuario ingresa como primer valor un nmero negativo ya no habr nada para sumar. En caso de entrar en el WHILE aumentamos el valor de la variable suma sumando su valor anterior al valor del nmero ledo, o sea, al valor de numero. En la lnea 18 volvemos a leer un nmero y el WHILE volver a su encabezado. Si el nuevo nmero ledo es mayor que 0 ya no habr iteracin y en caso contrario s. Luego de haber salido del WHILE mostramos al usuario el resultado de la suma. Bien, esto era para mostrar la idea de centinela. En este caso nuestro centinela es cualquier nmero negativo ingresado por el usuario ya que ste ser el que detenga la iteracin del WHILE. Veremos muchos ms ejemplos de centinelas de aqu en adelante.

Vladimir Rodrguez

48

Programacin estructurada en Pascal


Ejercicio: Muy bien, ahora quiero que modifiquen el programa de la pgina 44 cambiando la instruccin WHILE por un REPEAT. Un ejemplo ms complejo. Contador de palabras: Ahora veremos un ejemplo de programa que cuente la cantidad de palabras en una lnea de texto que ser ingresada por el usuario. Dicho texto debe terminar con un espacio y un punto s o s (centinelas): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 PROGRAM cuenta_palabras; Const ESPACIO= ' '; FIN= '.'; Var caracter: char; //Caracter ledo. cantidadPalabras: integer;//Cantidad de palabras contadas. BEGIN //Salteamos todos los espacios al inicio del texto. Repeat read(caracter) Until caracter <> ESPACIO; //En cada iteracin consumiremos una palabra. While caracter <> FIN do begin //Leemos caracteres hasta encontrar un espacio. Repeat read(caracter); Until caracter = ESPACIO; //Aumentamos en 1 el contador. cantidadPalabras:= cantidadPalabras + 1; //Salteamos los espacios que separan las palabras. Repeat read(caracter) Until caracter <> ESPACIO; end; //Del While.

writeln('La cantidad de palabras en el texto es: ',cantidadPalabras); 36 END. Les dejar como tarea que estudien este cdigo hasta que lo entiendan completamente. Fjense como implementamos distintos REAPEAT dentro de un WHILE y como usamos el procedimiento READ para siempre ir leyendo sobre la misma lnea. No olviden las constantes declaradas al inicio del programa. Los comentarios son su gran gua y eso es algo muy importante para un programador. Si deben trabajar con el cdigo de su compaero de trabajo debern ser capaces de entender sus cdigos basados en que saben la tarea que desempea su programa, las variables que declar tienen nombres mnemotcnicos y sus comentarios indican bien cada accin aunque sin extenderse o abusar de ellos. Todo esto es realmente muy importante que aprendan a implementarlo. Por si alguno de ustedes no lo sabe, un nombre mnemotcnico es aquel que ayuda a saber el propsito de una variable, por ejemplo, en este programa la variable que guarda el valor de cuantas palabras se cuentan se llama cantidadPalabras. Bien poda haberse llamado cont que es una abreviacin de contador o podra haber tenido cualquier otro nombre. Usen nombres mnemotcnicos aunque sean largos, esto ayuda a prescindir un poco de los comentarios y a que el cdigo sea ms entendible Ejemplo de captura de error: En el siguiente ejemplo veremos un programa simple que le pedir al usuario que ingrese un valor entero. En esta ocasin veremos como leer estos valores como caracteres y luego si son correctos pasarlos a enteros tal como debera ser. Primero veamos algo que debera haber nombrado ya hace bastante pero sin embargo decid aplazarlo hasta ahora.

Vladimir Rodrguez

49

Programacin estructurada en Pascal


En la 20 nombr por ah algo as como el ordinal de un elemento. Los tipos ordinales de Pascal son aquellos que estn acotados, o sea, que tienen un inicio y un final. Tal es el caso del tipo integer, que est acotado inferiormente por el valor -32768 y superiormente por MAXINT que vale 32767. Ninguna variable del tipo integer puede exceder estos valores. Si han activado el range checking tal como se los indiqu al inicio del tutorial deberan recibir un error en tiempo de compilacin al intentar guardar en una variable entera algn valor fuera del intervalo [-32768, 32767], de lo contrario el error lo obtendrn en tiempo de ejecucin. Tenemos el tipo char que contiene todos los caracteres existentes. Obviamente este tipo es acotado ya que tiene una cantidad finita de elementos. El tipo real no es acotado ya que posee una cantidad infinita de elementos. Nunca se puede determinar el siguiente a un real. Cul nmero es el siguiente a 1.5? Tal vez el 1.6? No porque antes est el 1.55, pero antes de ese est el 1.51, pero antes est el 1.501, y as podramos continuar infinitamente. Siempre entre dos nmeros reales cualesquiera hay infinitos reales. Esto en matemticas es llamado densidad de los reales. Lo importante aqu es hablar del ordinal de un carcter. Los caracteres estn todos incluidos, para Free Pascal (existen otras tablas), en una tabla llamada Tabla Ascii. Esta tabla le asigna a cada carcter un valor numrico segn su posicin. Para ver la tabla Ascii en el IDE simplemente vayan al men Tool Ascii table.

En esa imagen el cursor est posicionado sobre el smbolo @. Como vemos, a este carcter le corresponde el valor 64. Ese valor es el ordinal de @. Si nosotros tenemos un carcter cualquiera y queremos saber su ordinal debemos usar la funcin ord. Por ejemplo si escribiramos ord(@) obtendramos el entero 64. A la inversa tenemos la funcin chr que dado un entero nos devuelve su correspondiente carcter en la tabla. Si escribiramos chr(64) obtendramos como valor devuelto el carcter @. La funcin ORD transforma un carcter en entero, o sea, de un tipo char obtenemos un tipo integer. Esto es lo que usaremos para, dado un carcter numrico, obtener el entero de ese carcter, o sea, dado el carcter 1 obtener el nmero 1. Sin embargo no es tan fcil, observen ustedes en la tabla que al carcter 0 le corresponde el entero 48 ya que est en la posicin 49 de la tabla (la primera posicin es la 00). Al carcter 1 le corresponde el entero 49 y as sucesivamente. Por lo tanto si nosotros leyramos un carcter de la entrada estndar, suponiendo que el usuario ingres el 1, al hacer ORD(1) obtendramos el nmero 49 y no el nmero 1. A alguno de ustedes se les ocurre como, dado un carcter numrico, obtener su valor en entero? O sea, si me dan el 2 obtener el 2, si me dan el 8 obtener el 8, y as. Como pueden observar, los lugares de la tabla estn ordenados ascendentemente, por lo cual si al 0 le corresponde el 48, al 1 le corresponde el 49, al 2 el 50 y as hasta el 9 que le corresponde el 57. Entonces que pasa si al ordinal de cualquier carcter numrico le resto el ordinal de 0? Por ejemplo, si me dan el 0, resto ese ordinal con el ordinal de 0: Ord(0)-Ord(0)= 48 48= 0. Obtuve el entero 0. Ahora si me dieran el carcter 1 y a su ordinal le resto el ordinal de 0: Ord(1)-Ord(0)= 49 48= 1. Obtuve el entero 1. De tener el 9 y restarle su ordinal al ordinal de 0 tendra: Ord(9)-Ord(0)= 57 48= 9. Obtuve el entero 9. NOTA: El ordinal de un entero es el mismo entero: Ord(57)= 57. El ordinal de un boolean es 1 para TRUE y 0 para FALSE.

Vladimir Rodrguez

50

Programacin estructurada en Pascal


Vayamos al ejemplo entonces. Le pediremos al usuario que ingrese un entero, pero lo leeremos como caracter. Si los caracteres ledos difieren de los numricos le diremos al usuario que hay error, sino, transformaremos los caracteres a enteros. Para este programa usaremos la funcin EOLN que es TRUE cuando el cursor de la entrada estndar est en el fin de la lnea y FALSE en caso contrario. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 PROGRAM enteros; Var car: char; //Caracter ledo. entero: integer; //Guardar el valor en entero. error: boolean; //TRUE si el usuario no ingresa un entero. BEGIN primera_vez:= true; //Mostramos un mensaje al usuario y leemos la entrada. write('Ingrese un entero: '); read(car); //Damos la condicin de error. error:= (ord(car)<48) or (ord(car)>57); If not error then entero:= ord(car)-ord('0'); //Leemos hasta el fin de lnea o hasta que haya error. while (not eoln) and (not error) do begin //Leemos el siguiente caracter. read(car); //Verificamos que el caracter sea uno numrico. error:= (ord(car)<48) or (ord(car)>57); If not error then entero:= (entero*10)+(ord(car)-ord('0')); end; If not error then writeln('El entero ingresado es: ',entero) else writeln('No ha introducido un entero.'); END.

Como primer ejercicio tienen que entender este programa y modificarlo para que funcione con REPEAT. No continen hasta no ser capaces de resolver todos estos ejercicios. Ejercicio2: Determinen cules de los siguientes segmentos de cdigo producen la misma salida al ser ejecutados: a) i := 1; j := 2; REPEAT Write(i, j); i := i + 1; j := j + 1 UNTIL j <= 3; c) i := 1; REPEAT Write(i, i + 1); i := i + 1 UNTIL i <= 3; b) i := 1; j := 1; WHILE (i <= 3) AND (j <= 2) DO BEGIN Write(i, j + 1); i := i + 1; j := j + 1 END;

Vladimir Rodrguez

51

Programacin estructurada en Pascal


Ejercicio3: Se desea tener un programa que calcule el saldo de una cuenta. Supongan que los datos son ledos de la entrada estndar y que constan de renglones, cada uno de los cuales contiene una letra en la primera columna, seguida de un valor real. El ltimo rengln contiene nicamente la letra X en la columna uno. El primer rengln contiene la letra A y el saldo anterior de una cuenta de cheques. Los dems renglones contienen la letra D y el importe de un depsito o la letra R y el importe de un retiro. Escriban un programa que determine el saldo exacto de la cuenta despus de procesar las transacciones. Asumimos que las entradas sern siempre correctas. Ejemplo: A 1200.35 D 64.12 R 390.00 R 289.67 D 13.02 R 51.07 X El saldo final es 546.75 Ejercicio4: Dado un fragmento de texto que debe ser ledo de la entrada estndar, todo en una lnea, y terminado por el caracter $ (centinela), determine y exhiba las consonantes y vocales que aparecen duplicadas en forma contigua. Por ejemplo, el texto llama al chico que lee$ tiene una consonante doble (ll) y una vocal doble (ee) y se debera desplegar: ll ee. (Todas las letras son minsculas).

Ejercicio5: Realicen las funciones de una calculadora simple. Los datos de entrada sern una secuencia de dgitos enteros y los operadores +, *, / y -, seguida de un signo =. Hagan caso omiso de los espacios en blanco. Los operadores se aplican en el orden en que aparecen en los datos de entrada, o sea que olvdense de la precedencia, y producen resultados enteros, o sea, si bien se ingresa el operador de la divisin con el smbolo /, el comportamiento es el de DIV. Asuman que se ingresa al menos un nmero. Ej. de entrada: 4 + 3 / 2 * 8 - 4 = Ej. de salida: 20 Como ven, las operaciones se fueron realizando en el orden en el que aparecan. Primero 4+3 que es 7, eso lo dividimos entre 2 (div) que es 3, luego eso multiplicado por 8 que es 24 y luego eso menos 4 que es 20. Una verdadera calculadora habra hecho primero 3/2 que con DIV da 1 y luego eso por 8 que da 8. Luego hara 4+8-4 que es igual a 8. Sin embargo programar eso requiere ms herramientas de las que poseen. Ejercicio6 (DIFICIL): Escriban un programa que lea una letra y una oracin de la entrada estndar (de una sola lnea), y calcule la cantidad de palabras que terminan con la letra y estn en la oracin dada. Asuman que la oracin siempre terminar con un punto y que las palabras estarn separadas solo por espacios (no habr comas ni nada de eso). Asuman tambin que la oracin tendr siempre al menos una palabra. Ejemplos: Letra: s Oracin: La cualidad indispensable para un buen cocinero es la puntualidad pero es tambin la de los invitados. Salida: 4 Letra: r Oracin: Un discpulo de quien jams se pide nada que no pueda hacer nunca hace todo lo que puede. Salida: 1 Letra: o Oracin: No basta tener buen ingenio lo principal es aplicarlo bien. Salida: 4 Modifiquen su programa para que cuente las palabras que comienzan con la letra dada. Este es un ejercicio que los har pensar y luchar mucho. Intenten hacerlo bajo todos los medios posibles. Todo lo dado hasta ahora basta y sobra para lograrlo. Si no logran realizarlo escrbanme y les enviar la solucin para que la estudien, pero no tiene caso leer un programa ya hecho si ustedes no intentan realizarlo primero poniendo todas las ganas de aprender. Este manual es para ustedes y requiere todo su esfuerzo. No hay otro medio para aprender a programar. Mi esfuerzo fue escribir esto, ustedes practiquen y practiquen, pregntenme sus dudas a mi cacilla de correo y sigan intentando. Los frutos se vern al final.

Vladimir Rodrguez

52

Programacin estructurada en Pascal

TERCERA PARTE

Introduccin a los TIPOS definidos por el programador. Subrangos y Arreglos.

Vladimir Rodrguez

53

Programacin estructurada en Pascal Introduccin:


Hasta ahora hemos visto, en las dos primeras partes de este tutorial, como crear programas que puedan hacer una cosa u otra en funcin de ciertas condiciones, como hacer que repitan ciertas instrucciones tambin de forma condicional, entre otras cosas. En todos esos programas hemos usado variables de distintos tipos, sin embargo siempre han sido tipos primitivos de Pascal, o sea, los que ya estn predefinidos por el lenguaje. Sin embargo es posible que el programador defina tipos propios que pueden contener datos ms complejos que simples nmeros, caracteres o cadenas. Obviamente esto no es totalmente libre, pero dada nuestra imaginacin podemos crear tipos realmente muy complejos y que contengan mucha informacin. Los posibles tipos que podemos crear son: Subrangos, Arreglos, Conjuntos, Enumerados, Registros y Punteros. Todos excepto Punteros, al igual que los tipos primitivos, corresponden a tipos estticos de Pascal. Esto significa que declarada una variable de uno de esos tipos se asignar de la memoria el espacio suficiente para albergar el mayor valor posible. Este espacio de memoria estar en uso aunque nosotros no usemos la variable declarada o aunque usemos solo una parte de la informacin que esta pueda guardar. Este espacio de memoria se asigna ya al compilar el programa, o sea, en tiempo de compilacin. Los Punteros corresponden a un tipo dinmico. Esto es que, podremos pedir memoria cuando la necesitemos y devolverla cuando ya no la usemos. Este ser el ltimo tema de este tutorial.

Vladimir Rodrguez

54

Programacin estructurada en Pascal Subrangos:


Muy bien, el primer tipo a definir por el usuario que veremos es llamado subrango. Este es el tipo ms sencillo de declarar. Consiste en crear un Subrango de uno de los tipos primitivos ordinales de Pascal. Por ejemplo, un Subrango de los enteros podran ser los naturales, ya que estos son lo enteros de 0 en adelante (algunos los toman de 1 en adelante). Los tipos se declaran antes que las variables pero luego que las constantes. Para ello debemos indicar mediante la palabra reservada TYPE que haremos declaracin de tipos. Veamos un ejemplo de declaracin de subrangos: Type Naturales= 0..MAXINT; Mes= 1..12; Decimal= 0..9; Minusculas= 'a'..'z'; Digito= '0'..'9'; Mayusculas= 'A'..'Z'; Aqu hemos declarado seis tipos Subrango diferentes. Como ven la sintaxis es bien sencilla, luego de la palabra TYPE se declaran todos los tipos necesarios de esta manera: Identificador= valor_inicial..valor_final; En este ejemplo tenemos el tipo Naturales que contendr valores enteros entre 0 y MAXINT. Luego est el tipo Mes que contendr enteros entre 1 y 12. Decimal contendr valores entre 0 y 9. Luego vemos tres subrangos de caracteres: Minusculas que contendr los caracteres de la a a la z. Esto es porque las letras estn ordenadas segn la Tabla Ascii ascendentemente y sabemos que a<z. Digito contendr los caracteres del 0 al 9. Notar que Digito contiene los caracteres numricos y Decimal los valores enteros de esos nmeros. No es lo mismo. Finalmente tenemos el tipo Mayusculas que contiene caracteres de la A a la Z. Dado que estos son tipos, para usarlos debemos declarar variables de ese tipo: Type Naturales= 0..MAXINT; Mes= 1..12; Decimal= 0..9; Minusculas= 'a'..'z'; Digito= '0'..'9'; Mayusculas= 'A'..'Z'; Var letraMin: Minusculas; numero: Naturales; letraMay: Mayusculas;

Como ven es la misma sintaxis que para declarar una variable de tipo primitivo, le damos un identificador, dos puntos y luego el nombre del tipo. Esto significa que la variable letraMin podr tomar valores de la a a la z ya que es del tipo Minusculas. Como el Subrango Minusculas corresponde a un Subrango de caracteres, letraMin se comportar como una variable char con la diferencia de que no podr tomar valores fuera del rango indicado por Minusculas. Si esto sucede tendremos un error en tiempo de ejecucin. Si han activado Range checking como se los indiqu al inicio del tutorial, el compilador verificar esto en la medida de lo posible y se los advertir, pero no siempre podr hacerlo. Por ejemplo, si ustedes hacen read(letraMin) el compilador no podr asumir que el usuario puede ingresar un carcter fuera del rango y por tanto compilar correctamente, pero si hacen, letraMin:= A les advertir su error. Hay ms casos de esto, pero lo vern en la prctica. Lo mismo sucede para los subrangos Decimal, Mes y Naturales, que son subrangos de integer. Las variables de estos tipos funcionarn como variables enteras con la diferencia de que deben tomar valores dentro de los rangos establecidos. Visto de esta manera no puedo incentivarlos mucho con el uso de los subrangos, sin embargo veremos que resultan tiles para definir Arreglos, que es el tema que viene a continuacin. Lo que puedo decirles es que al definir un Subrango ustedes podrn estar seguros de que sus variables tendrn los valores adecuados. Claro que ustedes deben encargarse de que estas no tomen valor por fuera del rango establecido.

Vladimir Rodrguez

55

Programacin estructurada en Pascal Arreglos:


Declaracin: Muy bien, ahora s se viene algo ms interesante. Este es un tema muy importante y debern aprenderlo bien, ya que los arreglos son estructuras usadas para casi todo y en la mayora de los lenguajes. Un arreglo es una tabla compuesta por celdas que contienen, todas, valores de un mismo tipo. *------*------*------*------*-----*-----*-----*-----*-----* | 23 | 34 | 0 | -12 | 6 | 9 | 11 | -2 | 34 | *------*------*------*------*-----*-----*-----*-----*-----* 1 2 3 4 5 6 7 8 9 Ese es un ejemplo de un arreglo de enteros compuesto por nueve celdas. Cada celda tiene un valor distinto (pueden no serlo) y cada una es independiente de las dems. Como pueden ver todas las celdas estn numeradas del 1 al 9. Estos valores son llamados subndices y son los que usaremos para dirigirnos a una celda especfica. Veamos primero cmo se declara un arreglo: Identificador= array[Subrango] of tipo; Debemos indicar un nombre para el arreglo (identificador), luego, al igual que para los subrangos va un signo de igual (=) y la palabra reservada array (arreglo en ingls) seguida inmediatamente por un Subrango entre parntesis rectos [] el cual indicar la dimensin del arreglo (cuantas celdas tendr). Luego colocamos la palabra reservada of y un tipo para los valores que habr en cada celda. Este tipo puede ser uno primitivo de Pascal o uno definido anteriormente por el programador. Veamos algunos ejemplos: El arreglo dibujado arriba podra estar declarado como: Arreglo1= array[1..9] of integer; En este ejemplo le dimos el nombre Arreglo1. Declaramos directamente entre los parntesis rectos un Subrango. La dimensin de ese Subrango indica la dimensin del arreglo, en este caso el Subrango va de 1 a 9 por tanto contiene 9 elementos. Esto indica que el arreglo tendr nueve celdas. Es importante notar que esto indica solo la dimensin del arreglo y no el tipo de datos que contendr, o sea, Arreglo1 no contendr datos que solo vayan de 1 a 9 sino que contendr cualquier entero en sus celdas ya que su tipo est declarado luego de of y es integer. El Subrango entre parntesis rectos, adems de indicar cuntas celdas tendr el arreglo, tambin indica cmo se numeran. Arreglo1 tendr 9 celdas numeradas del uno al nueve, sin embargo, de haberse declarado Arreglo1= array[10..19] of integer; sera igual al anterior solo que sus nueve celdas estaran numeradas del 10 al 19, o de haberse declarado de esta manera Arreglo1= array[a..i] of integer; seguira teniendo nueve celdas solo que estaran identificadas de la a a la i. Lo ms comn es numerarlas del 1 en adelante y es lo recomendable. Tal como hemos declarado esos arreglos estamos declarando sus dimensiones con subrangos annimos, o sea, declarando estos justo dentro de los parntesis rectos sin darles nombre alguno. Sin embargo tambin es posible colocar dentro de estos parntesis un Subrango ya declarado anteriormente. Por ejemplo: Type Decimal= 0..9; Arreglo1= array[Decimal] of integer; Como ven, teniendo declarado antes el Subrango Decimal es posible utilizarlo para definir la dimensin y numeracin del arreglo. En este caso Arreglo1 tendr 10 celdas numeradas del 0 al 9. Tambin es posible hacer esto Type Decimal= 0..9; Arreglo1= array[Decimal] of Decimal; En este caso, el arreglo tiene 10 celdas numeradas del 0 al 9 y cada una puede contener datos del tipo Decimal. Siempre es posible utilizar algn tipo para definir otro s y solo s el tipo a utilizar est definido anteriormente. No sera posible utilizar Decimal para definir el arreglo si declarramos este Subrango ms abajo que el arreglo. Un arreglo es un tipo y por tanto va declarado luego de la palabra Type tal como se ve en estos dos ejemplos. Veamos ahora ms ejemplos de arreglos:

Vladimir Rodrguez

56

Programacin estructurada en Pascal


Type rango = 33..90; arr1 = array [char] of integer; (* 256 celdas *) arr2 = array [33..90] of real; arr3 = array [integer] of char; (* demasiado grande! *) arr4 = array [rango] of boolean; Tenemos un Subrango de enteros que va de 33 a 90. Luego tenemos arr1 que es un arreglo de 256 celdas (cantidad total de caracteres) cuyos ndices van de a a z donde cada una puede contener cualquier entero. arr2 que es un arreglo de 57 celdas numeradas del 33 al 90 donde cada una puede contener cualquier real. Luego tenemos arr3 que pretendera ser un arreglo de unas 65536 celdas numeradas desde el -32768 hasta el 32767 donde cada una podra contener caracteres. Este es un arreglo exorbitantemente grande, ocupara muchsima memoria y provocara muchos problemas. Adems no es para nada tico crear este tipo de estructuras. Finalmente tenemos arr4 que tiene 57 celdas numeradas del 33 al 90 donde cada una es un booleano que puede valer TRUE o FALSE. Utilizacin de arreglos: Hasta ahora solo hemos visto como se declara un arreglo y lo que significan las distintas declaraciones, sin embargo hace falta trabajar con ellos, y su sintaxis es un poco distinta a lo que venimos acostumbrados. Veremos un primer ejemplo donde crearemos un arreglo de enteros de 10 celdas cuyos ndices van del 1 al 10 y a cada celda le daremos el mismo valor que su ndice, o sea, a la primera le daremos el valor 1, a la segunda el 2 y as sucesivamente: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 PROGRAM arreglos; Type arr= array[1..10] of integer; Var arreglo1: arr; BEGIN arreglo1[1]:= 1; arreglo1[2]:= 2; arreglo1[3]:= 3; arreglo1[4]:= 4; arreglo1[5]:= 5; arreglo1[6]:= 6; arreglo1[7]:= 7; arreglo1[8]:= 8; arreglo1[9]:= 9; arreglo1[10]:= 10; END.

En la lnea 3 indicamos que comenzar la declaracin de tipos para, luego, en la lnea 4 declarar el tipo arr que ser un arreglo de 10 celdas numeradas del 1 al 10 del tipo entero. Como arr es un tipo su propsito es declarar variables de ese tipo, por lo tanto en la lnea 7 declaramos la variable arreglo1 del tipo arr. Podemos, al igual que con los tipos primitivos, declarar tantas variables como queramos de cualquier tipo que nosotros mismos definamos; en este caso tenemos solo una, pero podra tener ms y cada una sera independiente. Bien, en la lnea 9 comienza nuestro programa, el cual consta de diez lneas de asignacin donde en cada una le damos un valor a cada celda del arreglo. Veamos esto con detalle, es bien sencillo. Cada celda del arreglo funciona como una variable independiente, por tanto, en ese arreglo tenemos diez variables del tipo integer. Para referirnos a una celda debemos dar el nombre de nuestro arreglo (no el nombre del tipo sino el de la variable de ese tipo) seguido por el ndice entre parntesis rectos de la celda a la que queremos ir. De este modo, en la lnea 10, al escribir arreglo1[1]:= 1 estamos diciendo que vaya a la primera celda de arreglo1 y le asigne el valor 1. La sintaxis genrica sera Variable_del_tipo_arreglo[indice_de_la_celda] con lo cual nos referiramos a cualquier celda. Recordar que cada una es una variable independiente, por tanto esa declaracin es como si fuera el nombre de la variable y funciona igual que cualquier otra variable, valga la redundancia. Todo lo que sigue del programa es asignar a las celdas restantes el valor que queremos y termina nuestro programa. Sin embargo no es muy til tener que escribir instruccin por instruccin para dar un valor a cada celda. Imaginen un arreglo de 1000 celdas, tendramos un programa de 1000 lneas solo en asignaciones. Veamos el mismo programa pero asignando los mismos valores a cada celda de una forma ms inteligente:

Vladimir Rodrguez

57

Programacin estructurada en Pascal


1 2 3 4 5 6 7 8 9 10 11 12 13 PROGRAM arreglos; Type arr= array[1..10] of integer; Var arreglo1: arr; i: integer; BEGIN For i:=1 to 10 do arreglo1[i]:= i; END.

Hemos sustituido las 10 lneas de asignacin por una instruccin FOR que va de 1 a 10. Fjense que hemos colocado la variable de control i dentro los parntesis rectos que indican el ndice de nuestras celdas. De este modo, cuando i valga 1 estaremos hablando de la primera celda, cuando i pase a valer 2 estaremos hablando de la segunda celda, y as sucesivamente hasta 10. En este caso hemos asignado a cada celda el mismo valor de su ndice, pero esto podra no ser as. Este arreglo dibujado sera: *-----*-----*-----*-----*-----*-----*-----*-----*-----*-----* | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | *-----*-----*-----*-----*-----*-----*-----*-----*-----*-----* 1 2 3 4 5 6 7 8 9 10 Ahora veamos lo mismo pero asignando el doble del ndice a cada celda: 1 2 3 4 5 6 7 8 9 10 11 12 13 PROGRAM arreglos; Type arr= array[1..10] of integer; Var arreglo1: arr; i: integer; BEGIN For i:=1 to 10 do arreglo1[i]:= i*2; END.

De este modo arreglo1 ahora quedara as: *-----*-----*-----*-----*-----*-----*-----*-----*-----*-----* | 2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | *-----*-----*-----*-----*-----*-----*-----*-----*-----*-----* 1 2 3 4 5 6 7 8 9 10 Dentro de los parntesis rectos que indican el ndice del arreglo es posible, como hemos visto ya, colocar el valor del ndice, una variable del tipo correcto o, como no hemos visto an, una expresin que d cmo resultado un valor del tipo correcto y que est dentro del rango de ndices posibles. Es muy importante que lo que est dentro de los parntesis rectos nunca exceda el rango en que est numerado el arreglo. Si en este ejemplo nosotros escribiramos For i:=1 to 11 do arreglo1[i]:= i*2; se producira un error cuando i alcanzara el valor 11 y el programa se cerrara abruptamente ya que la celda 11 no existe. Si han activado Range checking lo ms probable es que el compilador les avise antes, pero esto no es siempre seguro ya que no siempre es detectable que podemos estar salindonos del arreglo. Veamos un nuevo ejemplo del mismo programa, solo que ahora los ndices sern caracteres y a cada celda le asignamos el valor del ordinal de su ndice. No olviden que el arreglo es de enteros.

Vladimir Rodrguez

58

Programacin estructurada en Pascal


1 2 3 4 5 6 7 8 9 10 11 12 13 PROGRAM arreglos; Type arr= array[a..j] of integer; Var arreglo1: arr; i: char; BEGIN For i:=a to j do arreglo1[i]:= ord(i); END.

De este modo nuestro arreglo quedara as: *-----*-----*-----*-----*-----*-----*-----*-----*-----*-----* | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | *-----*-----*-----*-----*-----*-----*-----*-----*-----*-----* a b c d e f g h i j

Hacer WRITE y READ de un arreglo: Si quisiramos desplegar un arreglo en la pantalla, o sea, que se nos muestren todos sus valores, debemos escribir celda por celda. En el ejemplo anterior tenamos el arreglo llamado arreglo1. Como primer impulso para escribirlo en pantalla uno tendera a hacer algo como esto write(arreglo1); y sin embargo eso no es posible. De hacerlo tendrn un error en tiempo de compilacin en el cual el compilador se les quejar por no poder escribir o leer variables de ese tipo. Esto es porque un arreglo es una estructura de datos y no un valor especfico. Por este motivo es que debemos escribir celda por celda. No se olviden que cada celda es como una variable ms y funciona del mismo modo. Veamos entonces como mostrar el arreglo de nuestro ejemplo anterior: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 PROGRAM arreglos; Type arr= array[a..j] of integer; Var arreglo1: arr; i: char; BEGIN For i:=a to j do arreglo1[i]:= ord(i); For i:=a to j do Write(arreglo1[i], ); END.

La nica diferencia entre este programa y el anterior es que agregamos un FOR que en cada iteracin escribe el valor de una de las celdas. Verifiquen esto ustedes mismos. Ejercicio: Modifiquen este programa para que con un solo FOR asigne los valores al arreglo y lo muestre en pantalla.

Del mismo modo, si quisiramos hacer read de un arreglo para que el usuario ingrese los valores de cada celda debemos hacerlo para cada una por separado. Ejercicio: Realicen un programa en el cual exista un arreglo de enteros de cinco celdas de modo que el usuario sea quin ingrese los valores para cada celda. Deben utilizar una instruccin FOR para ello.

Vladimir Rodrguez

59

Programacin estructurada en Pascal


Declaracin annima de un arreglo: Los arreglos que hemos visto hasta ahora los hemos declarado como tipos de modo que podemos declarar muchas variables de ese tipo. Sin embargo, a veces sucede que sabemos que vamos a usar un nico arreglo en nuestro programa y nada ms. Dado este caso no es necesario declarar el arreglo como tipo sino hacerlo de forma annima, directamente como variable. Veamos esto con el programa anterior ya que tenemos un nico arreglo en este: 1 PROGRAM arreglos; 2 3 Var 4 arreglo1: array[a..j] of integer; 5 i: char; 6 7 BEGIN 8 For i:=a to j do 9 arreglo1[i]:= ord(i); 10 11 For i:=a to j do 12 Write(arreglo1[i], ); 13 END. Como ven este programa es igual al anterior solo que hemos quitado la declaracin de tipos y hemos declarado el arreglo directamente como variable. De este modo solo se usar como arreglo1 y no como tipo por lo cual no podremos declarar variables como en los casos anteriores. No est mal si declaran siempre los arreglos como tipo, pero tengan en cuenta que un arreglo como tipo ocupa ms memoria que uno declarado annimamente. Si han declarado un tipo array el programa guardar memoria para recordar que existe un tipo definido por ustedes y qu datos puede contener y luego tambin guardar memoria para cada variable que declaren de ese tipo. Si lo hacen de forma annima solo guardar memoria para esa variable y punto. Un programa que utiliza mucha memoria es menos eficiente, al igual que uno que realiza demasiadas instrucciones o tareas. Siempre es importante tratar de que el programa haga el menor trabajo posible para que sea ms veloz y requiera menos recursos de la computadora para trabajar. Yo no voy a dedicarme a ensearles acerca de la eficiencia de los programas ya que este tutorial est dirigido a personas que recin estn aprendiendo, pero ya vayan teniendo en cuenta que este es un aspecto muy importante. De todos modos en algunos casos nombrar la mejor forma de realizar una tarea eficientemente.

Recorriendo arreglos: Ya sabemos como crear un arreglo y acceder a sus celdas para asignarles valores, leer estos desde la entrada o escribirlos. Tambin sabemos que cada celda funciona como una variable independiente y que siempre podemos acceder a la que queramos si sabemos como estn numeradas las celdas. Es por esto que conviene siempre que los ndices vayan de 1..N, o sea de 1 hasta N donde N es la cantidad de celdas del arreglo. Esto ayuda a evitar confusiones y hace todo mucho ms entendible. Sin embargo pueden hacerlo de otra manera si consideran que para cierto caso les resulta ms til. Muchas veces resulta necesario recorrer un arreglo, ya sea para buscar un elemento de l o para trabajar de algn modo con los valores de sus celdas, de otro modo para qu lo habramos creado entonces? Aunque les dej esto como ejercicio, espero lo hayan hecho antes de llegar aqu, veremos un ejemplo donde el usuario ingresa 10 valores enteros para un arreglo y luego nosotros desplegaremos stos para mostrrselos y adems le mostraremos la suma de ellos: 1 2 3 4 5 6 7 8 9 10 11 PROGRAM sumaCeldas; Const N= 10; //Dimensin del arreglo. Type arr= array[1..N] of integer; Var arreglo1: arr; i, suma: integer;

Vladimir Rodrguez

60

Programacin estructurada en Pascal


12 13 BEGIN 14 //Mensaje para el usuario. 15 write('Ingresa ,N, enteros: '); 16 17 //Leemos un valor para cada celda. 18 For i:=1 to N do 19 read(arreglo1[i]); 20 21 //Dejamos una lnea en blanco. 22 writeln; 23 24 //Mensaje al usuario. Mostramos su ingreso. 25 write('Usted ha ingresado: '); 26 For i:=1 to N do 27 write(arreglo1[i],' '); 28 29 //Iniciamos suma en 0 ya que an no hemos sumado nada. 30 suma:=0; 31 32 //Recorremos todo el arreglo sumando los valores a suma. 33 For i:=1 to N do 34 suma:= suma + arreglo1[i]; 35 36 //Mostramos el resultado al usuario. 37 writeln; 38 writeln('La suma de los valores es: ',suma); 39 END. Lo primero a destacar en este ejemplo es el uso de la constante N cuyo valor es 10. Es simplemente la que usaremos para declarar el Subrango que declara la dimensin del arreglo. De este modo la usaremos tambin en las iteraciones FOR para recorrer todas las celdas del arreglo. Si luego debiramos modificar nuestro programa para que el usuario ingrese 20 valores en vez de 10 solo debemos cambiar el valor de N en su declaracin de la lnea 4 y todo funcionar perfectamente. De lo contrario deberamos cambiar un 10 por un 20 cada vez que iterramos con el arreglo, al declararlo, etc. En la lnea 17 tenemos un FOR que leer un valor para cada celda del arreglo. Dada esa declaracin el usuario puede ingresar de a un valor he ir presionando enter, o ingresar los 10 valores separados por espacio en una misma lnea y presionar enter al final. Esto es posible ya que hemos usado el procedimiento read que lee un valor y deja el cursor en la misma lnea. De haber usado readln deberamos ingresar un valor por lnea. Les dejo el resto del programa a ustedes. Ahora veremos un ejemplo donde el usuario ingresa 10 valores enteros en un arreglo y el programa le mostrar el mayor de todos ellos: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 PROGRAM arreglos; Const N= 10; //Dimensin del arreglo. Type arr= array[1..N] of integer; Var arreglo1: arr; i, mayor: integer; BEGIN //Mensaje para el usuario. write('Ingresa ',N,' enteros: '); //Leemos un valor para cada celda. For i:=1 to N do read(arreglo1[i]); //Dejamos una lnea en blanco. writeln;

Vladimir Rodrguez

61

Programacin estructurada en Pascal


24 //En un principio el mayor valor es el primero. 25 mayor:= arreglo1[1]; 26 27//Ahora recorremos el resto del arreglo buscando el mayor valor. 28 For i:=2 to N do 29 begin 30 If arreglo1[i]>mayor then 31 mayor:= arreglo1[i]; 32 end; 33 34 //Informamos al usuario. 35 writeln('El mayor valor ingresado es: ',mayor); 36 END. Lean ustedes mismos este cdigo. Seguro son capaces de entenderlo muy bien. Bsqueda de un elemento: En este ejemplo veremos un programa en el que el usuario ingresa 10 enteros que guardaremos en el arreglo y luego le pediremos que ingrese otro valor. Buscaremos ese valor en el arreglo. Si est ah lo notificaremos y en caso contrario notificaremos que no est: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 PROGRAM BusquedaArreglo; Const N= 10; //Dimensin del arreglo. Type arr= array[1..N] of integer; Var arreglo1: arr; i, valorBuscado: integer; exito: boolean; BEGIN //Mensaje para el usuario. write('Ingresa ',N,' enteros: '); //Leemos un valor para cada celda. For i:=1 to N do read(arreglo1[i]); //Dejamos una lnea en blanco. writeln; //Leemos el valor a buscar en el arreglo. write('Ingresa el valor que deseas buscar: '); readln(valorBuscado); //Inicializamos nuestra variable ndice en 0. i:=0; {Iteramos hasta encontrar el valor o hasta recorrer todo el arreglo sin hallarlo} Repeat //Aumentamos un ndice. i:= i + 1; exito:= arreglo1[i]=valorBuscado; Until (exito) or (i=N); writeln; //Mostramos el mensaje correspondiente. If exito then writeln('El valor est en el arreglo.') else writeln('El valor no est en el arreglo.'); END.

Vladimir Rodrguez

62

Programacin estructurada en Pascal


Lo importante aqu est a partir de la lnea 30 donde inicializamos i en 0 ya que ser nuestro ndice. En la lnea 33 declaramos un REPEAT que aumentar nuestro ndice de bsqueda y luego se fijar si el valor buscado es igual al de la celda en que estamos posicionados. En ese caso exito ser true y la iteracin terminar. En caso contrario volveremos a aumentar i en 1 y nos fijaremos en la nueva posicin. La iteracin terminar al encontrar el elemento o al recorrer todo el arreglo sin hallarlo. Es importante destacar el uso del REPEAT aqu. Como primera cosa sabemos que iteraremos al menos una vez ya que debemos fijarnos al menos en la primera celda del arreglo, por eso us un REPEAT y no un WHILE. Alguno podr preguntarse y por qu no usaste un FOR para recorrer el arreglo como has hecho hasta ahora? Bien, veamos como quedara ese REPEAT si fuera un FOR For i:=1 to N do exito:= arreglo1[i]=valorBuscado; If exito then Writeln(El valor est en el arreglo.) Else Writeln(El valor no est en el arreglo.); Con el FOR recorreremos todo el arreglo siempre. La bandera booleana se volver true al hallar el elemento. Funciona perfectamente al igual que el REPEAT, ahora piensen esto. Imaginen que tenemos un arreglo de 500 celdas y el valor que buscbamos estaba en la celda nmero 86. Con el REPEAT recorreremos solo las primeras 86 celdas del arreglo y nos detendremos ya que al encontrar el elemento no nos interesa lo dems. Con el FOR, al encontrar el elemento la bandera ser true pero an as recorreremos las 500 celdas. Esto hace al programa trabajar de ms cuando no es necesario y le resta mucha eficiencia. Piensen en un arreglo de miles y miles de celdas, por ejemplo, una base de datos de Google en donde estn guardadas casi todas las webs del mundo. Sera mejor recorrer la base de datos hasta encontrar el elemento o recorrerla toda siempre? Es importante que comprendan esto. Aunque ya les dije que no les hara mucho hincapi con esto de la eficiencia, tambin dije que en ciertas ocasiones mencionara el modo de realizar ciertas tareas de la forma ms eficiente posible. Deben notar que el programa anterior se detendr ante el primer encuentro con el valor buscado sin interesarse en si se repite luego.

En la pgina siguiente hay una serie de ejercicios. No continen con el tutorial hasta que sean capaces de realizarlos todos, o de lo contrario, no podrn con los temas que vendrn a continuacin

Ejercicio1: Escriban un programa que lea diez enteros de la entrada estndar y guarde estos en un arreglo. El programa debe indicar el mayor de ellos y el ndice de la posicin en la que aparece, as como tambin, el menor de ellos y su posicin. En caso de que se repita un valor mostrarn el ndice de la primera celda en que aparezca. Asumimos que siempre se ingresan enteros en la entrada estndar. Ejemplo1: Ingrese 10 enteros: 2 3 1 4 5 10 6 7 8 9 El mayor entero es 10 en la posicin 6 El menor entero es 1 en la posicin 3 Ejemplo2: Ingrese 10 enteros: 2 3 2 20 5 20 6 7 8 9 El mayor entero es 20 en la posicin 4 El menor entero es 2 en la posicin 1

Ejercicio2: Este ejercicio conlleva cierta dificultad, sobretodo porque trabajarn con dos arreglos a la vez, cada uno de distinto tamao. Dada la definicin de tipo para representar cadenas de caracteres de largo M y N : CONST N = . . .; CONST M = . . .; { M < N } . . . TYPE CadenaM = ARRAY[1..M] Of Char;

Vladimir Rodrguez

63

Programacin estructurada en Pascal


CadenaN = ARRAY[1..N] Of Char; Implementen un programa que lea dos cadenas de la entrada estndar de largo M y N respectivamente, y determine si la primer cadena ocurre como parte de la segunda cadena. El programa debe funcionar para cualquier valor positivo que puedan tomar M y N, considerando la restriccin M < N. Ustedes mismos definan los valores de las constantes.Ejemplo de entrada para N=6, M=3: tor totora Ejemplo de salida: El texto 'tor' se encuentra dentro del texto 'totora'. Ejemplo de entrada: tos totora Ejemplo de salida: El texto 'tos' no se encuentra dentro del texto 'totora'.

Ejercicio3: Tiene una dificultad similar al anterior. Dada la definicin de tipo para representar cadenas de caracteres de largo N y M:

CONST N = . . .; CONST M = . . .; . . . TYPE CadenaM = ARRAY[1..M] Of Char; CadenaN = ARRAY[1..N] Of Char;

1. 2.

Escriban un programa que lea dos cadenas de largo M y N respectivamente, e imprima un mensaje en la salida estndar indicando si alguna letra en la primera palabra ocurre en la segunda. Escriban un programa que lea dos cadenas de largo M y N respectivamente, y determine si todas las letras en la primera palabra ocurren en la segunda.

Como ya saben, siempre que un ejercicio les de verdaderos problemas no tienen ms que escribirme a mstrvladi@hotmail.com explicndome sus dudas y les responder en breve. Siempre intenten todo lo que puedan y prueben bien sus programas antes de dar por terminado un ejercicio.

Vladimir Rodrguez

64

Programacin estructurada en Pascal Arreglos multidimensionales:


Los arreglos que hemos visto hasta ahora son unidimensionales, o sea, de una nica dimensin. Se dice esto ya que se requiere una nica coordenada (ndice) para ubicar una celda del mismo. Sin embargo es posible definir arreglos de dos dimensiones (2D), de tres dimensiones (3D) y ms. Aqu veremos ejemplos de arreglos de hasta tres dimensiones ya que no requerimos de ms para trabajar, sin embargo muchos programas usan arreglos de N dimensiones. Como nosotros existimos en un espacio de dimensin 3 solo podemos ver grficamente arreglos de dimensin 3 o menor.

Arreglos bidimensionales: Comencemos por ver arreglos de dos dimensiones. Estos dibujarn una tabla de datos del mismo tipo, tambin conocidas matemticamente como matrices. Hay dos maneras de declarar arreglos bidimensionales, una es declarar un arreglo de un arreglo, o sea, un arreglo cuyas celdas sean tambin arreglos. Esta es la forma ms fea de hacerlo y la que menos recomiendo, pero existe. Vemoslo en un ejemplo: 1 PROGRAM BIDIMENSIONAL; 2 3 Type 4 arr1= array[1..5] of integer; 5 Tabla= array[1..7] of arr1; 6 7 Var 8 i, j: integer; 9 matriz: Tabla; 10 11 BEGIN 12 For i:= 1 to 7 do 13 For j:= 1 to 5 do 14 matriz[i,j]:= 0; 15 END. En la lnea 4 vemos un tipo arr1 que es un arreglo de 5 celdas de enteros. En la lnea 5 vemos el tipo Tabla que es un arreglo de 7 celdas del tipo arr1, o sea que cada celda es un arreglo de 5 celdas. Si dibujramos Tabla al igual que lo hicimos antes tendramos 7 celdas del 1 al 7, esto estara indicando cuantas filas tiene nuestra tabla. Si desplegamos cada celda de Tabla estaramos abriendo hacia la derecha 5 lugares con lo cual estaramos indicando las columnas de nuestra tabla. Columnas(j)

0 0 0 0 0 0 0

0 0 0 0 0 0 0

0 0 0 0 0 0 0

0 0 0 0 0 0 0

0 0 0 0 0 0 0

Filas(i)

Ese sera el dibujo de Tabla, como ven hay 7 filas (lneas horizontales) y 5 columnas (lneas verticales). El 0 corresponde a la posicin (3,3) de la tabla ya que est en la fila 3 y en la columna 3. Siempre para una tabla se especificarn las coordenadas de una celda nombrando primero el nmero de filas y luego el de columnas. En la lnea 9 del ejemplo declaramos la variable matriz del tipo Tabla. El trabajo con los arreglos bidimensionales es idntico al de los arreglos unidimensionales. Cada celda es una variable independiente y para acceder a cada una simplemente nombramos nuestro arreglo y damos entre parntesis rectos las coordenadas de nuestra celda separadas por comas. La forma genrica sera as: Variable_arreglo[fila,columna] de este modo, si quisiramos ir a la celda que est en la fila 7 y en la columna 4 deberamos escribir matriz[7,4].

Vladimir Rodrguez

65

Programacin estructurada en Pascal


En nuestro programa de ejemplo asignamos a cada celda el valor 0. Como ven debemos usar dos FOR anidados para recorrer una tabla, uno para recorrer las filas y otro para las columnas. Vean que el subrango en arr1 indica cuntas columnas tendr la matriz y en subrango en Tabla indica cuntas filas. Una sintaxis alterna para acceder a una celda de nuestra tabla es la siguiente: Variable_arreglo[fila][columna] y por tanto si, usando esta sintaxis, quisiramos acceder a la fila 7 y la columna 4 deberamos escribir matriz[7] [4]. No recomiendo esta sintaxis. Veamos ahora la segunda forma de declarar un arreglo bidimensional, la cual es la que yo recomiendo que usen: 1 PROGRAM BIDIMENSIONAL; 2 3 Type 4 Tabla= array[1..7,1..5] of integer; 5 6 Var 7 i, j: integer; 8 matriz: Tabla; 9 10 BEGIN 11 For i:= 1 to 7 do 12 For j:= 1 to 5 do 13 matriz[i,j]:= 0; 14 END. Como ven en la lnea 4 hemos declarado el tipo Tabla en el cual hemos incluido dos subrangos entre los parntesis rectos separados por coma. El primer subrango (1..7) indica la cantidad de filas y el segundo (1..5) la cantidad de columnas que tendr la matriz. Esto siempre es as. Como ven, de este modo queda todo mucho ms claro. NOTA: La cantidad de celdas de un arreglo bidimensional es igual al resultado de multiplicar la cantidad de filas por la cantidad de columnas. Como ejercicio quiero que modifiquen ese programa para que despliegue en la salida estndar la matriz. En este caso aparecer una tabla de 0 como esta: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Esto no es muy difcil y radica explcitamente en el uso de FOR.

Ejercicio2: Modifiquen los programas anteriores para que, si el usuario no ingresa un entero, notifiquen el error y vuelvan a pedir el valor correcto.

Ejercicio3 Se llama matriz cuadrada a toda aquella matriz que tiene tantas filas como columnas, o sea, si tiene 5 filas tiene 5 columnas. La transpuesta de una matriz cuadrada es aquella matriz que tiene como columnas lo que antes eran filas. O sea, si tenemos una matriz cuadrada A, una matriz cuadrada B es transpuesta de A si las columnas de B son iguales a las filas de A, o sea, si se satisface que B[i,j]=A[j,i] para todos los valores posibles de i y j.

Vladimir Rodrguez

66

Programacin estructurada en Pascal


Ejemplo. Sea A de 5 filas y 5 columnas como se muestra en la figura, veamos como sera su transpuesta B: 1 0 1 5 2 A 2 3 0 0 1 1 4 3 2 2 4 0 1 2 2 5 0 1 1 2 1 2 3 4 5 B 0 1 0 1 0 1 0 1 0 1 5 4 3 2 1 2 2 2 2 2

Como ven, lo que en A eran filas, en B son columnas. La primera fila de A que contiene los valores 1, 2, 3, 4 y 5 es la primera columna de B 1, 2, 3, 4 y 5, y as sucesivamente. Escriban un programa que calcule la transpuesta de un arreglo de nmeros reales con cinco renglones y cinco columnas. Los valores de la matriz se leen desde la entrada estndar. El resultado se debe imprimir en la salida estndar. Recuerden la relacin B[i,j]=A[j,i] para que sean transpuestas. Este ejercicio no es muy complicado. Tal vez lo peor de esto es que trabaja con una propiedad matemtica de las matrices y para aquellos que no lo han estudiado puede resultar difcil de comprender. An as creo que no deberan tener problemas. Arreglos tridimensionales: Esto es bsicamente lo mismo. Se declaran exactamente igual solo que ahora habr tres subrangos entre parntesis rectos y por ende deberemos colocar tres coordenadas para indicar cual celda deseamos ver (una coordenada para la fila (altura), otra para la columna (largo) y otra para el eje (ancho)). Hago esta aclaracin porque si bien un arreglo bidimensional dibuja una tabla, uno tridimensional dibuja un prisma y por tanto debemos decir cuan a lo alto, largo y ancho queremos posicionarnos.

Esto es un arreglo bidimensional de 5 filas y 8 columnas. Visto de este modo es un rectngulo donde la cantidad de filas son su altura y la cantidad de columnas su largo. Este es un arreglo de 5x8.

As podramos visualizar un arreglo tridimensional de 5x8x6. Como ven es un arreglo de tablas que estaran todas bien pegadas formando un prisma. Nosotros debemos indicar en qu fila y columna est nuestra celda y en cual tabla de todas. Siempre indicamos [fila, columna, tabla]. Esto es un intento de que puedan visualizar un arreglo tridimensional. El punto rojo correspondera a la posicin [4,8,3] por estar en la cuarta fila, octava columna de la tercera tabla. El azul correspondera a la posicin [1,3,6]. Hasta aqu llegamos con arreglos. Ahora les propondr un PROYECTO.

Vladimir Rodrguez

67

Programacin estructurada en Pascal REALIZANDO UN PROYECTO MASTER MIND


Bien, dado todo lo que saben hasta ahora les propongo realizar el siguiente programa. Se trata de un viejo juego conocido llamado Master Mind. Es un juego para dos personas, una hace de adivinador y la otra de pensador. El adivinador intentar adivinar un cdigo de cuatro letras, que solo el pensador conoce, en un nmero mximo de intentos determinado. Cada vez que el adivinador propone un cdigo, si no adivina, el pensador le dar pistas para que pueda adivinar. Estas pistas estarn dadas por dos notas, BUENOS y REGULARES. Veamos un ejemplo: Supongamos que el pensador se inventa el cdigo ABCD para que el otro jugador adivine. Como primer intento el adivinador presenta el cdigo AFGH. Como ven no ha acertado, pero una de las letras de su cdigo coincide con la del cdigo del pensador, por tanto hay una bien. Esa A corresponde a un BUENO ya que adems de ser la misma letra est en la misma posicin que en el cdigo del pensador, en este caso, en el primer lugar. Un REGULAR corresponde a una letra que esta en ambos cdigos pero en una posicin diferente. Por ejemplo, si para adivinar el ABCD el adivinador presentara el FAGH solo la letra A est en ambos cdigos, pero en el del pensador est en primer lugar y en el del adivinador est en segundo lugar. Ambas notas se presentan a la vez. Veamos un ejemplo suponiendo que las letras que puede haber en el cdigo van de la A a la F inclusive. Las letras pueden repetirse. El cdigo del pensador es FDDA: Primer intento: ABCD Buenos: 0 Regulares 2 Como ven no hay letras que coincidan en posicin, pero tenemos en el cdigo del adivinador una A que est en el primer lugar (en el del pensador est en el ltimo) y una D en ltimo lugar (en el del pensador est en segundo o tercer lugar) y corresponden cada una a un regular. Segundo intento: BADC Buenos: 1 Regulares: 1 Ahora la D coincide en el tercer lugar de ambos cdigos. Notar que en el cdigo del pensador hay tambin una D en el segundo lugar, pero esta no hace que la D del tercer lugar del cdigo del adivinador sea un regular ya que esta coincide con la D del tercer lugar. La A siegue estando en posiciones distintas. Tercer intento: EDAE Cuarto intento: EDAF Quinto intento: DDAF Sexto intento: FADD Sptimo intento: FDDA Buenos: 1 Regulares: Buenos: 1 Regulares: Buenos: 1 Regulares: Buenos: 2 Regulares: Buenos: 4 Regulares: 0 1 2 3 2

En este caso el adivinador ha ganado. Noten que si suman Buenos + Regulares el resultado siempre ser menor o igual al nmero de letras en el cdigo (en este caso 4) y slo ser igual si todas las letras en el cdigo del adivinador estn en el del pensador. Nunca puede ser mayor. Dadas las siguientes declaraciones: Const primeraLetra= A; ultimaLetra= F; largoCodigo= 4; maxIntentos= 10; Type Codigo= array[1..largoCodigo] of char; deben programar el Master Mind de modo que la CPU haga de pensador y el usuario de adivinador. El programa deber crear un cdigo al azar y luego el usuario intentar adivinarlo. Cada vez que el usuario ingrese un cdigo el programa le dar las notas correspondientes. Si el usuario adivina el programa debe mostrarle un mensaje de felicitaciones. Si el usuario llega la cantidad mxima de intentos sin adivinar, el programa debe notificarle que perdi y mostrarle cual era el cdigo que deba adivinar. Cada vez que el usuario ingrese un caracter que no corresponda al rango de letras del cdigo (A a F), o que ingrese un cdigo ms largo o ms corto que 4 caracteres el programa debe mostrar un mensaje de error y volver a pedir el ingreso del cdigo sin aumentar el intento actual del usuario. En cada momento el programa ir mostrando el intento actual. Veamos unos ejemplos de ejecucin: Dispones de 10 intentos para adivinar:

Vladimir Rodrguez

68

Programacin estructurada en Pascal


1)--> ABCD B2 R0 2)--> AFCD B2 R1 3)--> AFD ERROR 3)--> AFDFF ERROR 3)--> AFJD ERROR 3)--> A5FD ERROR 3)--> ACFD B3 R0 4)--> ACED B4 R0 FELICIDADES. HAS GANADO. En este ejemplo vemos que el programa primero despliega un mensaje para notificar al usuario de cuantos intentos mximos dispone para adivinar. Luego comienza el juego. El programa muestra el nmero de intento actual y una flecha. Luego se espera la entrada del usuario. El programa despliega las notas y pasa a la lnea siguiente mostrando el intento actual, la flecha y aguardando la entrada del usuario. Tambin vemos en el tercer intento que el usuario ingresa un cdigo ms corto de lo debido, eso es un ERROR. Muestra el mensaje y pasa a la siguiente lnea pero no aumenta el intento actual, seguimos en el tercero. Luego el usuario ingresa un cdigo ms largo de lo debido. Se notifica el error y volvemos a esperar un ingreso sin aumentar el nmero de intento. Luego el usuario ingresa un cdigo de cuatro letras pero con una J incluida, la cual no est en el rango comprendido entre A y F. Esto tambin es un error. Luego el usuario ingresa un cdigo con un 5 y este carcter tampoco est en el rango de A a F y por tanto es un ERROR. Como ven siempre seguimos en el tercer intento. Finalmente el usuario ingresa bien el cdigo y el programa contina. En el cuarto intento el usuario adivina el cdigo, se le informa de ello y as gana. Veamos un ejemplo en el que pierde: El cdigo del pensador es ADDB Dispones de 10 intentos para adivinar: 1)--> ABCD B1 R2 2)--> ABCE B1 R1 3)--> ABCF B1 R1 4)--> AFCD B1 R1 5)--> ABCC B1 R1 6)--> ABBA B1 R1 7)--> ABDB B3 R0 8)--> ADBB B3 R0 9)--> ADCB B3 R0 10)--> ADCB B3 R0 Lamentablemente has perdido. El cdigo era ADDB.

Crear un cdigo al azar y calcular los Buenos de un cdigo mostrado por el usuario no es muy difcil. La verdadera dificultad de esto estar a la hora de calcular los Regulares ya que cuando se repitan letras tendrn problemas para contabilizarlas una nica vez. Por ejemplo si el cdigo a adivinar es ADFD y se nos muestra el ABDB tenemos un Bueno y un Regular. La D est dos veces en el cdigo del pensador y una en el del adivinador, pero no corresponde a dos regulares, sino a uno. Otro caso es ADFD y ADBB. En este caso la A est bien y la D coincide en la segunda posicin, por tanto es un Bueno y no un Regular a pesar de que hay una D en la cuarta posicin del cdigo del pensador. Estas y muchas otras dificultades se les presentarn con este programa. Realmente deben ser capaces de realizarlo. Les llevar como mnimo una semana hacerlo bien, no se maten por hacerlo en menos tiempo, realmente cuesta. Esta vez tendrn muchas consultas que hacerme, as que escrbanme a mstrvladi@hotmail.com y pregunten todas las dudas que tengan. Existen muchsimas formas de realizar este programa. Su imaginacin es el lmite. Mucha suerte.

Vladimir Rodrguez

69

Programacin estructurada en Pascal

Vladimir Rodrguez

70

Programacin estructurada en Pascal

CUARTA PARTE

SUBPROGRAMAS: Procedimientos y Funciones

Vladimir Rodrguez

71

Programacin estructurada en Pascal Introduccin:


Bien, hasta ahora el tema ms complicado que hemos visto lo representan los arreglos (array); sin embargo entraremos ahora en temas un tanto ms difciles y que por ende requerirn ms trabajo por parte de ustedes a la hora de practicar. Yo intentar explicarlos lo ms detalladamente posible y de un modo entendible siempre partiendo de la base de que ustedes como lectores no tienen conocimiento alguno sobre programacin. Hasta el momento hemos visto programas que podan o no estar divididos en varios bloques. Por si no lo recuerdan llambamos bloque a aquella seccin de cdigo delimitada entre un BEGIN y un END. Cada bloque siempre contiene ms de una instruccin, de lo contrario no tendra sentido definirlo aunque es posible hacerlo, pero es visto por el programa como una nica instruccin. Del modo en que hemos venido programando, si nuestro programa tuviera que realizar la misma tarea ms de una vez nosotros deberamos escribir las mismas lneas de cdigo todas esas veces. Esto extiende muchsimo nuestro cdigo fuente dejndolo difcil de entender adems de complicar muchsimo la tarea del programador. Es por esto que existen dos estructuras muy importantes y potentes que forman a los llamados subprogramas (pequeos programas dentro del programa principal) conocidos como PROCEDIMIENTOS y FUNCIONES (en otros lenguajes, como Java, ambas estructuras se conocen como Mtodos). Estas estructuras comienzan con lo que en programacin se conoce como Modularizacin ya que como su nombre lo indica permiten formar mdulos de programa que se encargan de ciertas tareas especficas. De este modo el cdigo queda mucho ms entendible y compacto adems de lograrse una buena ordenacin del mismo. Es sumamente importante que entiendan todo este captulo antes de continuar si en verdad quieren lograr crear un buen programa, sea del tipo que sea, ya que los procedimientos y las funciones son bsicos para cualquier programador avanzado.

Vladimir Rodrguez

72

Programacin estructurada en Pascal Procedimientos:


Declaracin y llamado: Veamos primero los PROCEDIMIENTOS: Un Procedimiento ser un subprograma que se encargar de realizar una tarea especfica dentro del programa principal. Al igual que al programa principal, a los procedimientos se les asigna un nombre (identificador) con el cual podremos llamarlo luego para pedirle que realice su tarea. Un procedimiento se define de la siguiente manera PROCEDURE identificador(parmetros); Usamos la palabra reservada PROCEDURE para indicar que definiremos un procedimiento, luego le damos un nombre cualquiera que identifique su tarea o que nos sirva a nosotros como referencia. Seguido del nombre se colocan entre parntesis los parmetros que utilizar el procedimiento para trabajar (esto lo veremos dentro de poco) y finalmente un punto y coma. Todo esto compone lo que llamamos encabezado o firma del procedimiento. No pueden existir dos procedimientos con el mismo identificador ya que como ha sido hasta ahora y debera resultarles obvio, no pueden repetirse identificadores. Esto puede cambiar de un lenguaje a otro, pero no entraremos en esos detalles, concentrmonos en Pascal. Como ya he dicho, un procedimiento es un subprograma, o sea, un pequeo programa dentro del programa principal y por este motivo tendr una estructura casi idntica a la de este ltimo. Lo que quiero decir con esto es que, luego del encabezado del procedimiento, podremos definir CONSTANTES, TIPOS, VARIABLES e incluso otros subprogramas dentro. Tambin tendr un bloque principal delimitado entre BEGIN y END solo que este END terminar en punto y coma. Nunca olviden que el nico END que termina en punto es el del programa principal. Esta sera la estructura del programa principal con lo visto hasta el momento: PROGRAM Nombre_del_programa; Const //Declaramos constantes. Type //Declaramos tipos. Var //Declaramos variables. BEGIN //Bloque principal del programa. END. Veamos la estructura pero agregando el lugar donde se declaran los procedimientos y funciones: PROGRAM Nombre_del_programa; Const //Declaramos constantes. Type //Declaramos tipos. Var //Declaramos variables. {Declaracin de Procedimientos y Funciones} BEGIN //Bloque principal del programa. END. Veamos ahora la estructura de un procedimiento: PROCEDURE Nombre_del_procedimiento(parmetros); Const //Declaracin de constantes. Type //Declaracin de tipos. Var //Declaracin de variables. BEGIN {Bloque principal del procedimiento} END; Noten que la estructura es idntica a la del programa principal excepto por el encabezado y por el hecho de que el END del bloque principal termina en punto y coma. A esa estructura debera aadirle la declaracin de funciones y procedimientos, pero esta va en el mismo lugar que en el bloque del programa principal y no creo que haga falta mostrarles donde va. No se pongan nerviosos, pronto entendern mejor todo esto. Veamos un ejemplo sencillo en el que pedimos al usuario que ingrese su Nombre, su Apellido, su Edad, su Documento de Identidad y su Direccin. Luego mostraremos los datos ingresados pero separados por una lnea formada por guiones y luego varias lneas en blanco. Veremos la versin sin procedimiento y luego la versin con procedimiento.

Vladimir Rodrguez

73

Programacin estructurada en Pascal


Para este ejemplo en particular usaremos el tipo primitivo STRING, que lee cadenas de caracteres desde la entrada estndar. Lo correcto a los efectos de este manual sera leer carcter a carcter y guardar estos en un arreglo para formar la palabra, pero esto se los pedir luego en un ejercicio. 1 PROGRAM Datos_de_Usuario; 2 3 Const 4 separador='-'; 5 lineas_a_saltear= 4; 6 7 Var 8 nombre, apellido, documento, direccion: string; 9 i: integer; 10 11 BEGIN 12 //Pedimos los ingresos al usuario. 13 Write('Ingresa tu nombre: '); 14 readln(nombre); 15 write('Ingresa tu apellido: '); 16 readln(apellido); 17 write('Ingresa tu documento: '); 18 readln(documento); 19 write('Ingresa tu direccin: '); 20 readln(direccion); 21 22 //Realizamos la primera separacin. 23 For i:=1 to 20 do 24 write(separador); 25 For i:=1 to lineas_a_saltear do 26 writeln; 27 28 //Escribimos el nombre del usuario. 29 writeln('NOMBRE: ',nombre); 30 31 //Realizamos la segunda separacin. 32 For i:=1 to 20 do 33 write(separador); 34 For i:=1 to lineas_a_saltear do 35 writeln; 36 37 //Escribimos el apellido del usuario. 38 writeln('APELLIDO: ',apellido); 39 40 //Realizamos la tercera separacin. 41 For i:=1 to 20 do 42 write(separador); 43 For i:=1 to lineas_a_saltear do 44 writeln; 45 46 //Escribimos el documento del usuario. 47 writeln('DOCUMENTO: ',documento); 48 49 //Realizamos la cuarta separacin. 50 For i:=1 to 20 do 51 write(separador); 52 For i:=1 to lineas_a_saltear do 53 writeln; 54 55 //Escribimos la direccin del usuario. 56 writeln('DIRECCIN: ',direccion); 57 END. Este es un programa muy sencillo y no deberan tener ninguna dificultad al leerlo. An as explicar lo que hace as luego se entiende perfectamente el ejemplo con procedimiento. Declaramos en las primeras lneas dos constantes: separador, que es del tipo char inicializada con el guin; este carcter ser el que dibuje una lnea separadora, esto es bien simple, escribimos unos 20 guiones en la misma lnea y ya. Luego est la constante lineas_a_saltear que es del tipo integer inicializada con el nmero 4 y es la que utilizaremos para indicar cuantas lneas en blanco dejaremos entre dato y dato.

Vladimir Rodrguez

74

Programacin estructurada en Pascal


Luego declaramos cuatro variables del tipo string para leer los datos del usuario, una por cada dato. Como ya dije, el tipo string lee los datos en forma de cadenas de caracteres. Esto implica que si uno ingresa un valor 4556 no ser el nmero entero 4556 sino la cadena de caracteres 4556. Es ideal para leer palabras o frases, pero no hablaremos de su uso en este manual ya que la idea aqu es que ustedes aprendan a programar estructuradamente y entiendan como funcionan las herramientas ms primitivas. De este modo lograrn desarrollar una gran habilidad para programar y sern capaces de resolver grandes problemas con pocas herramientas, que muchas veces ser a lo que tendrn que enfrentarse. La otra variable declarada es i, del tipo entero, y ser la que usaremos como variable de control para los FOR. Desde la lnea 13 a 20 inclusive solo pedimos al usuario que ingrese sus datos y los leemos desde la entrada estndar. Esto no implica ninguna dificultad para ustedes. En la lnea 23 declaramos un FOR que simplemente dibuja los 20 guiones y en la lnea 25 declaramos el FOR que se encarga de dejar lneas en blanco, tantas como la constante lineas_a_saltear indique en su valor. Estos dos FOR se repetirn varias veces durante el cdigo, cada vez que necesitemos dibujar la lnea de guiones y dejar lneas en blanco. Como podrn ver, usaremos cuatro veces estas dos instrucciones en nuestro programa. Realmente esto resulta estpido ya que quedara ms prolijo si no dejramos lneas en blanco para presentar los datos del usuario, pero la intencin de este ejemplo es ver la necesidad de los procedimientos de una manera sencilla, ya que un buen ejemplo sera muy complejo y no es adecuado presentarlo en el momento en el que ustedes estn intentando aprender una nueva herramienta y que resultar bastante difcil de comprender si no se trabaja con cuidado. Ahora veamos el mismo ejemplo pero con un procedimiento llamado Saltear que se encargue de realizar la tarea de los dos FOR, o sea, dibujar la lnea de guiones y de dejar lneas en blanco: 1 PROGRAM Datos_de_Usuario; 2 3 Const 4 separador='-'; 5 lineas_a_saltear= 4; 6 7 Var 8 nombre, apellido, documento, direccion: string; 9 i: integer; 10 11 Procedure Saltear(); 12 Begin 13 For i:= 1 to 20 do 14 Write(separador); 15 For i:= 1 to lineas_a_saltear do 16 Writeln; 17 End; 18 19 BEGIN 20 //Pedimos los ingresos al usuario. 21 Write('Ingresa tu nombre: '); 22 readln(nombre); 23 write('Ingresa tu apellido: '); 24 readln(apellido); 25 write('Ingresa tu documento: '); 26 readln(documento); 27 write('Ingresa tu direccin: '); 28 readln(direccion); 29 30 //Realizamos la primera separacin. 31 Saltear(); 32 //Escribimos el nombre del usuario. 33 writeln('NOMBRE: ',nombre); 34 35 //Realizamos la segunda separacin. 36 Saltear(); 37 38 //Escribimos el apellido del usuario. 39 writeln('APELLIDO: ',apellido); 40 41 //Realizamos la tercera separacin. 42 Saltear(); 43 44 //Escribimos el documento del usuario. 45 writeln('DOCUMENTO: ',documento);

Vladimir Rodrguez

75

Programacin estructurada en Pascal


46 47 48 49 50 51 52 END.

//Realizamos la cuarta separacin. Saltear(); //Escribimos la direccin del usuario. writeln('DIRECCIN: ',direccion);

Bien, este programa es idntico al anterior en el sentido de que realiza exactamente la misma tarea. Como suceda en la versin anterior, repetamos cuatro veces la declaracin de los FOR que se ocupan de dibujar los guiones y saltear lneas. Ahora lo haremos solo una vez dentro del procedimiento Saltear. Las declaraciones de constantes y variables quedan idnticas a las anteriores. Ahora la diferencia principal est en que luego de las variables declaramos a nuestro procedimiento. Vemoslo detalladamente: Procedure Saltear(); Begin For i:= 1 to 20 do Write(separador); For i:= 1 to lineas_a_saltear do Writeln; End; Tenemos su encabezado que consta simplemente de la palabra reservada procedure y luego de su identificador Saltear seguido por los parntesis. En este caso estos parntesis no tienen nada dentro porque este procedimiento no utiliza parmetros, eso lo veremos ms adelante. A pesar de que no existan parmetros, es conveniente incluir los parntesis vacos, aunque pueden no hacerlo si lo prefieren. Luego del encabezado podramos haber declarado constantes, variables, tipos y/u otros procedimientos, pero no hace falta para este ejemplo tan sencillo, as que procedemos directamente a iniciar el bloque principal con la palabra Begin. A partir de aqu se escriben todas las instrucciones que realizar el procedimiento, las cuales pueden ser lo que a ustedes se les ocurra, lo que les haga falta y que saben utilizarn en ms de una ocasin. No olviden que un procedimiento es un pequeo programa dentro del programa principal y por lo tanto admite exactamente las mismas reglas. En este caso nuestro procedimiento contiene a los dos FOR de antes y nada ms. Cerramos su bloque principal con End; con lo cual nuestro programa sabe que all termina la declaracin de Saltear. Bien, ya tenemos nuestro procedimiento que se encarga de dibujar la lnea de guiones y de dejar lneas en blanco, ahora solo debemos llamarlo cada vez que lo necesitemos. Esto es bien fcil, solo escribimos su nombre en el lugar en el que deseamos que realice su tarea y entre parntesis colocamos los parmetros que utilizaremos, en este caso como no hay parmetros solo dejamos los parntesis vacos aunque bien podramos no incluirlos. En este ejemplo vemos las cuatro llamadas en las lneas 31, 36, 42 y 48. En este caso en particular no ahorramos muchas lneas de cdigo al utilizar el procedimiento, pero como ya dije, un verdadero ejemplo sera muy complejo y en realidad los procedimientos y funciones utilizados llegan a estar formados por cientos y cientos de lneas. Como ven, utilizando un procedimiento solo hace falta escribir una nica vez una tarea especfica volvindose el cdigo ms legible y ms fcil de mantener en caso de errores o actualizacin. Cuando nuestro programa principal llega, por ejemplo, a la lnea 31, regresa a la 12 (o a aquella donde est el BEGIN del bloque principal del procedimiento) y realiza una por una las instrucciones all indicadas hasta llegar al END que finaliza el bloque del procedimiento. Pueden ver esto si utilizan el DEBUGER paso a paso utilizando F7 en vez de F8 para avanzar. Como ya expliqu antes, F7 ingresa dentro de los subrprogramas en el paso a paso y F8 no.

Variables Globales y Locales. Introduccin al Alcance de Identificadores: En nuestro ejemplo vimos que nuestro procedimiento no posea ninguna variable declarada dentro. Sin embargo tambin vemos que la nica variable que usa es i y la nica constante es lineas_a_saltear adems de que ambas solo son usadas por el procedimiento y por nadie ms. Dado este caso bien podramos haberlas declarado adentro del procedimiento para que se entienda que solo sern usadas por este y por nadie ms. Las variables declaradas en el programa principal son llamadas variables globales y las que se declaran dentro de un procedimiento o una funcin son llamadas variables locales o internas. Las variables globales son visibles dentro de todo el programa, o sea, uno puede hacer referencia a ellas en cualquier parte del cdigo. Por ejemplo, si tenemos una variable global entera llamada x podremos asignarle un valor en cualquier parte de nuestro programa, o sea, escribir x:=10 en la lnea nmero 5 y luego en la lnea nmero 1258 escribir x:= 25 o utilizarla en expresiones o para que el usuario ingrese un valor, etc., por citar ejemplos tontos. Las variables locales son visibles solo dentro del procedimiento o la funcin en que son declaradas. Esto implica que solo podamos hacer referencia a variables locales dentro del bloque principal de su subprograma y n fuera. Por ejemplo, si tenemos una variable string llamada nombre dentro de un procedimiento podremos utilizarla como queramos solo dentro su bloque principal, por ejemplo con una instruccin readln(nombre), pero si escribimos la misma instruccin u

Vladimir Rodrguez

76

Programacin estructurada en Pascal


otra que implique a dicha variable fuera del bloque principal de su subprograma el compilador no la reconocer porque no la ve y nos dir que no est declarada. Si vemos al programa principal como una mquina, por ejemplo, un vehculo, cada subprograma corresponder a alguna parte que se encarga de una tarea especfica. Por ejemplo, nosotros podemos conducir y utilizar un reproductor de CDs a la vez. La unidad lectora de CDs del vehculo es como un procedimiento que se encarga de reproducir los CDs cuando nosotros lo dispongamos, pero aunque la podemos utilizar cuando queramos y colocar el CD que queramos (este sera nuestro parmetro), no podemos ver ni utilizar sus piezas internas (que seran sus variables locales). De este modo si se rompe la unidad reproductora simplemente debemos ir directamente a ella para repararla sin necesidad de tocar nada ms del vehculo. Lo mismo sucede con nuestros subprogramas. 1 PROGRAM Datos_de_Usuario; 2 3 Var 4 nombre, apellido, documento, direccion: string; 5 6 Procedure Saltear(); 7 Const 8 separador='-'; 9 lineas_a_saltear= 4; 10 11 Var 12 i: integer; 13 Begin 14 For i:= 1 to 20 do 15 Write(separador); 16 For i:= 1 to lineas_a_saltear do 17 Writeln; 18 End; 19 20 BEGIN 21 //Pedimos los ingresos al usuario. 22 Write('Ingresa tu nombre: '); 23 readln(nombre); 24 write('Ingresa tu apellido: '); 25 readln(apellido); 26 write('Ingresa tu documento: '); 27 readln(documento); 28 write('Ingresa tu direccin: '); 29 readln(direccion); 30 31 //Realizamos la primera separacin. 32 Saltear(); 33 //Escribimos el nombre del usuario. 34 writeln('NOMBRE: ',nombre); 35 36 //Realizamos la segunda separacin. 37 Saltear(); 38 39 //Escribimos el apellido del usuario. 40 writeln('APELLIDO: ',apellido); 41 42 //Realizamos la tercera separacin. 43 Saltear(); 44 45 //Escribimos el documento del usuario. 46 writeln('DOCUMENTO: ',documento); 47 48 //Realizamos la cuarta separacin. 49 Saltear(); 50 51 //Escribimos la direccin del usuario. 52 writeln('DIRECCIN: ',direccion); 53 END. No solo las variables son visibles segn donde estn declaradas, las constantes y los tipos tambin pueden ser globales o locales. Como vemos en este ejemplo, he colocado las constantes de nuestro programa y la variable i dentro del procedimiento Saltear. Si ustedes quisieran referirse a i fuera del procedimiento tendran un error en tiempo de

Vladimir Rodrguez

77

Programacin estructurada en Pascal


compilacin indicndoles que no encuentra el identificador i. Esto es porque i no es visible fuera del procedimiento. Es como una pieza de nuestro reproductor de CDs, no podemos verlas ni utilizarlas. Esto garantiza que el procedimiento se dedique nicamente a su tarea y esta no pueda ser modificada accidentalmente por un cambio de valores o cosas por el estilo. Fjense que si tuviramos un programa de miles y miles de lneas donde solo existen variables globales, cuando nuestros subprogramas se dispongan a usarlas, si nosotros no nos dimos cuenta y las modificamos antes en algn lado del programa, realizarn errneamente sus tareas adems de que son totalmente dependientes de lo que sucede globalmente en el programa y por tanto de nuestra suma atencin en el momento de programar. Esto causa que el intentar corregir errores se vuelva una tarea ardua y tediosa cuando en realidad podra ser ms sencillo. En nuestro vehculo no sera aconsejable que funcionara mal el reproductor de CDs porque ser rompi el radiador, por ejemplo, sino que el reproductor es independiente y por ende no depende de las dems piezas del vehculo. A la inversa, no sera bueno que no funcionara el radiador si se nos rompe el reproductor. Esto se aplica a otras muchsimas partes, por supuesto. Ahora bien, no olvidemos que las variables globales son visibles en todo el programa y podemos usarlas tanto dentro como fuera de los subprogramas. En nuestro vehculo podramos decir que la batera es global ya que es usada por muchas partes y si esta falla todas esas partes fallarn. En realidad lo correcto sera decir que el sistema elctrico es un subprograma donde est declarada la batera y dentro de l tenemos a otros subprogramas como el reproductor de CDs, el claxon, las luces, los limpiaparabrisas, etc, y por tanto para todos estos subprogramas la batera resultara global, aunque no para el resto del vehculo. Dicho de otra manera. Todo lo declarado dentro de un subprograma es local al mismo y por ende solo visible dentro de este, pero resulta global a lo que est declarado all dentro. Siendo as, si tenemos un subprograma dentro del cual hay ms subprogramas, las variables declaradas dentro de l sern globales a sus subprogramas pero no sern visibles fuera de l. Veamos esto con declaraciones sencillas: PROGRAM alcance_identificadores; Var x, y: integer; Procedure Procedimiento1(); Var a, b: integer; Procedure Procedmiento2(); Var j, k: integer; Begin //Instrucciones Procedimiento2. End; Begin //Instrucciones Procedimiento1. End; BEGIN //Instrucciones programa principal. END. Este es un ejemplo genrico sencillo. Tenemos el programa principal y dos procedimientos, Procedimiento1 y Procedmiento2 de modo que el segundo est declarado dentro del primero. Estn las variables globales x e y declaradas en el programa principal y por ende visibles en cualquier parte del cdigo, dentro o fuera de cualquiera de los procedimientos. Declaradas en Procedimiento1 estn las variables a y b las cuales son visibles solo dentro de dicho procedimiento y no fuera. Como Procedmiento2 est declarado dentro de Procedimiento1 estas variables resultan globales para Procedmiento2, o sea que son visibles dentro de todo su cdigo. Finalmente dentro de Procedmiento2 estn declaradas j y k las cuales son solo visibles all dentro y en ningn otro lado. Ahora veamos este mismo ejemplo pero con un funcionamiento sencillo: 1 2 3 4 5 6 7 PROGRAM alcance_identificadores; Var x, y: integer; Procedure Procedimiento1(); Var

Vladimir Rodrguez

78

Programacin estructurada en Pascal


8 a, b: integer; 9 10 Procedure Procedmiento2(); 11 Var 12 j, k: integer; 13 Begin 14 x:= 10; 15 y:= 11; 16 a:= 1; 17 b:= 2; 18 j:= 20; 19 k:= 21; 20 21 write(x,' ',y,' ',a,' ',b,' ',j,' ',k); 22 End; 23 Begin 24 Procedimiento2(); 25 End; 26 27 BEGIN 28 Procedimiento1(); 29 END. Como ya deberan saber, dadas estas declaraciones, cualquier variable es visible en Procedimiento2 as que utilizamos este para inicializarlas todas con los valores que ven y luego utilizamos el mtodo WRITE para mostrar estos nmeros en pantalla separados por un espacio. Procedimiento1 lo nico que hace es llamar a Procedimiento2 y el programa principal lo nico que hace es llamar a Procedimiento1. Este programa podra resumirse solo a tener Procedimiento2 o incluso ni tenerlo, pero es para que aprendan esto del alcance de los identificadores de las variables. Ahora bien. Qu pasa si escribimos la instruccin de la lnea 21 fuera de Procedimiento2? Si lo hacemos dentro Procedimiento1 tendramos un error de compilacin ya que dentro del WRITE hacemos referencia a las variables j y k y estas solo son visibles dentro de Procedimiento2. Si lo hacemos fuera de Procedimiento1 tendramos un error del mismo tipo al anterior ya que hacemos referencia a las variables a, b, j y k que no son visibles fuera de sus procedimientos. Por este motivo el nico que puede mostrar en pantalla los resultados es Procedimiento2 ya que es donde son visibles todas las variables de nuestro programa. No hace falta inicializar todas las variables dentro de Procedimiento2. Veamos el mismo ejemplo pero inicializando cada variable dentro de su procedimiento para luego mostrar el resultado en pantalla: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 PROGRAM alcance_identificadores; Var x, y: integer; Procedure Procedimiento1(); Var a, b: integer; Procedure Procedmiento2(); Var j, k: integer; Begin j:= 20; k:= 21; write(x,' ',y,' ',a,' ',b,' ',j,' ',k); End; Begin a:= 1; b:= 2; Procedimiento2(); End; BEGIN x:= 10; y:= 11; Procedimiento1(); END.

Vladimir Rodrguez

79

Programacin estructurada en Pascal


Este programa produce exactamente la misma salida que el anterior. Solo hemos inicializado las variables en distintos lugares. Deben identificar bien cada bloque, o sea, cual pertenece al programa principal, cual a un procedimiento y cual al otro. Si no logran entender esto no deben continuar hasta que lo hayan logrado ya que esto forma parte de la base necesaria para entender subprogramas. Lo que viene a continuacin requiere que hayan comprendido donde puede visualizarse cada variable en dependencia de donde ha sido declarada.

Sombreado de Identificadores: Bien, continuemos con esto del alcance de los identificadores. Hasta ahora simplemente hemos visto que cada variable es visible dentro del cuerpo del subprograma en que ha sido declarada y no fuera. Ahora bien, la complicacin con esto comienza cuando tenemos una variable global con cierto nombre y luego en un subprograma tenemos una variable local con el mismo nombre. Pero como? No era que no pueden repetirse identificadores? En efecto, no pueden repetirse, pero como hemos visto, una variable local es visible solo dentro del subprograma donde se ha declarado y por tanto fuera de este es como si no estuviera declarada, como si no existiera, por lo tanto es posible declarar otra con el mismo nombre. Pero si la variable global es visible dentro de un subprograma, cuando adems declaramos dentro de este una variable local con el mismo nombre cmo sabemos a cual nos estamos refiriendo dentro del subprograma? Esto es simple pero genera muchas confusiones. Si tenemos una variable global con un nombre idntico al de una local, cuando dentro del subprograma nos referimos a ese identificador tiene precedencia la variable local, o sea, esta sombrea a la global dentro del subprograma. Veamos un ejemplo bien sencillo de entender: 1 PROGRAM sombreo_identificadores; 2 3 Var 4 X: integer; 5 6 Procedure sombreo(); 7 Var 8 X: integer; 9 10 Begin 11 X:= 10; 12 End; 13 14 BEGIN 15 Sombreo(); 16 END. En este ejemplo tenemos una variable global X y una local dentro del procedimiento sombreo tambin llamada X. Como vemos, dentro del procedimiento he inicializado X en 10. El programa principal lo nico que hace es llamar al procedimiento. Cul de las dos X vale 10? Como la inicializacin fue dictada dentro del procedimiento, al referenciar a X nos estamos dirigiendo a la X local y no a la global, por lo tanto la X que vale 10 es la interna al procedimiento y la otra no sabemos cuanto vale porque no le hemos dado ningn valor an. Ahora veamos otro ejemplito sencillo: 1 PROGRAM sombreo_identificadores; 2 3 Var 4 X: integer; 5 6 Procedure sombreo(); 7 Var 8 X: integer; 9 10 Begin 11 X:= 10; 12 Writeln(X); 13 End; 14 15 BEGIN 16 X:= 5; 17 Sombreo();

Vladimir Rodrguez

80

Programacin estructurada en Pascal


18 Write(X); 19 END. Ahora he inicializado ambas variables, la global con el valor 5 y la interna con el valor 10. Cmo ser la salida de este programa?

Parmetros: Pasaje por Valor:


Con lo visto hasta ahora acerca de los procedimientos no podemos hacer mucho ya que no resultan demasiado tiles. En la mayora de los casos nuestro programa ir realizando tareas y obteniendo resultados con dichas tareas, y muchas veces necesitaremos pasarle esos datos a los procedimientos para que trabajen con ellos. Si volvemos a nuestro ejemplo del vehculo y el reproductor de CDs, nosotros necesitamos introducir un CD para que este sea reproducido obteniendo como resultado la msica. Esto puede hacerse con las variables globales, pero como ya dije, lo correcto es hacer que el procedimiento sea independiente al resto del programa. Es por eso que existen los parmetros, para introducir datos al procedimiento y eventualmente para obtenerlos. Los parmetros no son ms que variables como las que ya conocemos y que funcionarn como variables locales al procedimiento, con dos pequeas diferencias: se declaran en el encabezado y no dentro del cuerpo del procedimiento; y se inicializan al entrar al procedimiento con los valores que nosotros pasemos como parmetros. Veamos esto en un ejemplo sencillo: 1. PROGRAM triangulo; 2. 3. Var 4. base, altura: real; 5. 6. Procedure calcularArea(b, h: real); 7. Begin 8. if (b>0) and (h>0) then 9. writeln('El rea del tringulo es: ',(b*h)/2:1:1) 10. else 11. writeln('ERROR. Ninguna dimensin de un tringulo puede ser menor o igual a 0.'); 12. End; 13. 14. BEGIN 15. //Pedimos el ingreso de datos al usuario. 16. write('Ingaresa el valor de la base: '); 17. readln(base); 18. write('Ingresa el valor de la altura: '); 19. readln(altura); 20. 21. //Llamamos al procedimiento calcularArea. 22. calcularArea(base,altura); 23. END. Este es un programa sencillo para calcular el rea de un tringulo, no muy diferente al que ya hemos creado. Tenemos dos variables reales globales, una para el valor de la longitud de la base del tringulo y otra para el valor de la longitud de la altura. Desde la lnea 15 hasta la 19 inclusive pedimos al usuario que ingrese los valores de estas dimensiones. Veamos el encabezado del procedimiento calcularArea. Entre parntesis tenemos la declaracin de dos variables reales, b y h. Como ven solo se trata de una declaracin como cualquier otra, solo que no lleva la palabra VAR delante (luego veremos que s puede llevarla pero solo para casos especiales). Esas variables, b y h, corresponden a los parmetros del procedimiento, en este caso dos, por lo tanto cuando lo llamemos debemos ingresarle dos valores para sus parmetros para que las variables b y h los tomen. Vean la llamada de la lnea 22: calcularArea(base,altura); Es igual a las anteriormente vistas con la diferencia de que ahora entre parntesis hemos colocado los valores de los parmetros, los cuales, en este caso, estn dados por las variables base y altura. El orden en el que se ingresan los parmetros en la llamada al procedimiento es el orden en el que se tomarn, por lo tanto base, que est en primer lugar, le dar su valor a b ya que es el primer parmetro declarado; y altura

Vladimir Rodrguez

81

Programacin estructurada en Pascal


le dar su valor a h ya que fue declarado en segundo lugar. Los parmetros se pasan separados por comas tal y como lo ven ustedes all. Tambin es posible pasar directamente valores como parmetros al procedimiento, por ejemplo, hacer una llamada de este estilo: calcularArea(10,20.33). Si ese fuera el caso b tomara el valor 10 y h el 20.33. Es por esto que hoy dije que los parmetros se inicializan en la llamada al procedimiento, ya que siempre tomarn los valores que se les pasen. No es posible pasar un nmero de parmetros distintos al declarado en el encabezado. Por ejemplo, calcularArea tiene dos parmetros y por tanto solo dos valores deben pasarse en su llamada, ni ms ni menos. Otra cosa muy pero muy importante es que sean compatibles los tipos de parmetros con los valores que se les pasan. En este caso los parmetros son ambos del tipo real y por tanto esperarn valores reales o enteros en la llamada, pero no podrn ir caracteres o cadenas de caracteres. Si lo hacen tendrn un error en tiempo de compilacin ya que el compilador se dar cuenta de que han introducido tipos incompatibles.

Declaracin de parmetros de tipos diferentes: El encabezado del procedimiento anterior era Procedure calcularArea(b, h: real); pero bien poda haber sido Procedure calcularArea(b: real; h: real); Es posible declarar los parmetros por separado indicando su tipo y utilizando el punto y coma para comenzar con la declaracin siguiente. Sin embargo resulta ms til declarar todos los parmetros de un mismo tipo especificando solo una vez dicho tipo, tal y como lo hice en el ejemplo del tringulo. Ahora veamos ejemplos de encabezados sencillos donde hay parmetros de tipos distintos: Procedure procedimiento1(a, b: real; x, y: integer; letra: char; nombre: string); Como ven tenemos seis parmetros, dos reales, dos enteros, un carcter y una cadena. Ese orden de declaracin deber respetarse para llamar al procedimiento: procedimiento1(un real, otro real, un entero, otro entero, un carcter, una cadena); Si cambian dicho orden tendrn un error de compilacin. Otro ejemplo: Procedure procedimiento2(a, b: integer; n: char; x: integer); Aqu hay cuatro parmetros, dos enteros, un carcter y otro entero. Por qu no declar todos los enteros en una sola declaracin? O sea, este encabezado bien podra ser Procedure procedimiento2(a, b, x: integer; n: char); pero aunque son los mismos parmetros el orden est en lugares diferentes y por tanto los valores se pasarn en dicho orden. En el primer ejemplo la llamada sera as: Procedimiento2(un entero, otro entero, un carcter, un entero); y en el segundo ejemplo sera as: Procedimiento2(un entero, otro entero, un entero, un carcter); Tengan mucho cuidado con esto ya que el orden de declaracin y el de invocacin deben ser iguales. A veces por una cuestin de entendimiento es mejor utilizar un encabezado como el del primer ejemplo. Veamos algo tonto pero tal vez les ayude a entender esto: Supongamos que tenemos un procedimiento del cual no nos interesa su funcionamiento pero toma como parmetros el nombre de dos usuarios y sus edades. Un encabezado podra ser este: Procedure usuarios(nombre1, nombre2: string; edad1, edad2: real);

Otro podra ser este:

Vladimir Rodrguez

82

Programacin estructurada en Pascal


Procedure usuarios(nombre1: string; edad1: real; nombre2: string;edad2: real); Dados los nombres de los parmetros en ambos se entiende que nombre1 y edad1 corresponden a un usuario y nombre2 y edad2 a otro. Sin embargo en la llamada, en el primer ejemplo introducimos los dos nombres y luego las dos edades en el orden correspondiente (usuario1, usuario2, edad de usuario1, edad de usuario2) mientras que en el segundo ejemplo introducimos el usuario, su edad, el otro usuario y su edad. Les presento ambos modelos para que los tengan en mente. Ustedes seleccionarn el ms adecuado o crearn los suyos propios segn lo vean necesario. Es importante que sepan que los parmetros pueden ser de cualquier tipo, incluso los declarados por ustedes mismos siempre que dichos tipos sean globales para el subprograma en cuestin.

Asignaciones de parmetros: Como ya dije antes, los parmetros funcionan como variables locales al procedimiento al que pertenecen y por lo tanto pueden usarse como tales. O sea, podemos asignarle valores a un parmetro, utilizarlo en una expresin, hacer READ y WRITE, etc. No creo que esto requiera de ejemplos ya que ustedes deben trabajar muy bien con las variables a estas alturas.

Parmetros Nominales y parmetros Efectivos: Llamamos parmetros nominales a los nombres (identificadores) que aparecen en el encabezado del procedimiento o funcin y parmetros efectivos a los que usamos en la llamada al subprograma, ya sean valores, variables o expresiones. En nuestro ejemplo del tringulo los parmetros nominales eran b y h, y los efectivos eran base y altura.

Hasta ahora hemos visto el mtodo de pasaje de parmetros por valor, o sea, nosotros le pasamos valores a los parmetros en la llamada al procedimiento y sus parmetros se inicializan con dichos valores para trabajar. Lo que sucede luego con los parmetros no influye en el resto del programa, solo en el interior del procedimiento, excepto claro que modifiquemos a propsito variables globales, cosa que no recomiendo. Entonces, si dices que no es recomendable modificar variables globales, cmo podemos obtener resultados de un procedimiento? Esa sera una buena pregunta. Si luego de calcular el rea de tringulo quisiramos seguir trabajando con ese valor, pero no queremos utilizar variables globales qu hacemos? All es donde entra el pasaje de parmetros por referencia, pero no hablar de ello todava, ya que es lo ms complicado de este tema. En vez de eso hablemos primero de las funciones.

Vladimir Rodrguez

83

Programacin estructurada en Pascal Funciones:


Declaracin y llamado: Las funciones no difieren casi en nada de los procedimientos. Tienen solo dos diferencias fundamentales: el encabezado, y que las funciones devuelven un valor como resultado de su trabajo. De este modo, para calcular el rea de un tringulo lo correcto es usar una funcin y no un procedimiento. Grbense esto bien: LAS FUNCIONES DEVUELVEN VALORES COMO RESULTADO, LOS PROCEDIMIENTOS NO. Veamos como se declara una funcin: Function nombre(parmetros): tipo; En vez de utilizar la palabra reservada Procedure utilizamos Function. Luego le damos un nombre y entre parntesis declaramos sus parmetros tal y como lo hacamos con los procedimientos. Luego de la declaracin de parmetros van dos puntos y el tipo de valor que devolver la funcin. Este tipo debe ser un tipo simple, o sea, no puede ser enumerado, arreglo (array), conjunto (set) ni registro (record). Todava no hemos hablado de algunos de ellos, pero ya lo haremos luego. Ahora veamos el ejemplo del rea del tringulo utilizando una funcin que la calcule y devuelva su valor: 1. PROGRAM triangulo; 2. 3. Var 4. base, altura, area: real; 5. 6. Function calcularArea(b, h: real): real; 7. Begin 8. if(b>0) and (h>0) then 9. calcularArea:= b*h/2 10. else 11. calcularArea:= 0; 12. End; 13. 14. BEGIN 15. //Pedimos el ingreso de datos al usuario. 16. write('Ingaresa el valor de la base: '); 17. readln(base); 18. write('Ingresa el valor de la altura: '); 19. readln(altura); 20. 21. //Llamamos a la funcin calcularArea. 22. area:= calcularArea(base,altura); 23. writeln('El rea del tringulo es: ',area:1:2); 24. END. El funcionamiento de este programa es bsicamente el mismo al del anterior con la diferencia de que en vez de un procedimiento usamos una funcin adems de que declaramos una nueva variable que contendr el rea del tringulo. Veamos el encabezado de la funcin: Function calcularArea(b, h: real): real; Como vemos hemos declarado dos parmetros tal como lo habamos hecho en el procedimiento. Ambos parmetros contienen valores reales. El tipo de la funcin lo hemos declarado como real y por tanto esta devolver un nmero como resultado de sus tareas. El tipo de la funcin no tiene nada que ver con el tipo de sus parmetros, en este caso da la casualidad de que todo es del tipo real, pero pueden ser cualesquiera siempre y cuando el de la funcin sea un tipo simple. Al igual que hacamos en el procedimiento, en la funcin verificamos primero que las dimensiones ingresadas sean mayores que 0, de lo contrario diremos que el rea vale 0 mediante la asignacin de la lnea 11. All pueden ver que utilizamos la funcin como si fuera una variable y le asignamos el valor 0. Vemos esto tambin en la lnea 9 donde calculamos el rea en caso de que las dimensiones sean vlidas y le asignamos a la funcin el valor de multiplicar el parmetro b por el parmetro h y dividir ese resultado entre 2.

Vladimir Rodrguez

84

Programacin estructurada en Pascal


La funcin puede usarse a la izquierda de una expresin de asignacin (:=) solo si estamos dentro de su bloque principal y solo cuando queramos asignarle el valor que nos devolver. Fuera de su cuerpo la funcin puede ser usada solo a la derecha de las expresiones de asignacin, ya sea para realizar clculos o para que otras variables tomen su valor, tal como sucede en la lnea 22 de nuestro programa. Mediante la expresin de asignacin area:= calcularArea(base,altura) estamos asignndole a la variable area el valor que devolver calcularArea con los parmetros ingresados. Otro modo de haber escrito este programa habra sido no declarar la variable area y escribir la instruccin WRITELN de la lnea 23 de esta manera: writeln('El rea del tringulo es: ', calcularArea(base,altura):1:2); Como pueden observar, incluimos dentro de la instruccin WRITE directamente la llamada a la funcin calcularArea para mostrar en pantalla su valor.

Funciones Booleanas: El tipo Boolean es un tipo simple que toma uno de dos valores posibles: TRUE (verdadero) o FALSE (falso). Esto por supuesto ustedes ya lo saben. Las funciones pueden ser del tipo boolean ya que como acabo de decir es un tipo simple. El hecho de que me tome un trabajo extra para tratarlas es para que ustedes puedan ver las formas ms comunes en las que estas son utilizadas. Ahora veremos el ejemplo del rea del tringulo donde tendremos dos funciones, una para verificar que lo ingresado por el usuario corresponde a dimensiones adecuadas para el tringulo, en tal caso la funcin devolver TRUE y en caso contrario FALSE. Si las dimensiones son correctas entonces llamaremos a la funcin para calcular el rea del tringulo para la cual solo nos limitaremos a hacer el clculo ya que siempre la llamaremos en caso de que los datos ingresados sean correctos. 1. PROGRAM triangulo; 2. 3. Var 4. base, altura, area: real; 5. 6. Function verificarDatos(b, h: real): boolean; 7. Begin 8. verificarDatos:= (b>0) and (h>0); 9. End; 10. 11. Function calcularArea(b, h: real): real; 12. Begin 13. calcularArea:= b*h/2; 14. End; 15. 16. BEGIN 17. //Pedimos el ingreso de datos al usuario. 18. write('Ingaresa el valor de la base: '); 19. readln(base); 20. write('Ingresa el valor de la altura: '); 21. readln(altura); 22. 23. If verificarDatos(base,altura) then 24. writeln('El rea es: ',calcularArea(base,altura):1:2) 25. else 26. writeln('Has ingresado alguna dimensin menor o igual a 0.'); 27. END. Este ejemplo debera de resultarles bien sencillo de entender. Tenemos dos funciones declaradas. Solo explicar el funcionamiento de la funcin verificarDatos: Como pueden ver tiene dos parmetros reales y la funcin es del tipo boolean. La sentencia de la lnea 8 es igual a la que se usa para las variables del tipo boolean, o sea, dicha sentencia es equivalente a escribir: If (a>0) and (h>0) then verificarDatos:= true else verificarDatos:= false;

Vladimir Rodrguez

85

Programacin estructurada en Pascal


Ambas formas funcionan de igual manera, pero la ms correcta es la que yo utilic en el programa. An as ustedes siempre tienen la libertad de utilizar las herramientas que prefieran. Veamos ahora el IF de la lnea 23: If verificarDatos(base,altura) then Como ya dije, las funciones pueden ser usadas como variables pero no pueden asignrsele valores fuera de su bloque principal. En este caso la estamos utilizando en el IF como una variable del tipo boolean y por ende estamos preguntando si es TRUE, recuerden que solo incluir el nombre de un boolean es preguntar por su veracidad, y para preguntar por su falsedad se utiliza el operador lgico NOT. Ahora veamos un ejemplo un poco ms complejo acerca del uso de una funcin booleanas. En este caso veremos una funcin llamada Pertenece la cual se encargar de verificar si un elemento pertenece o no a un arreglo. En caso afirmativo devolver TRUE y en caso contrario FALSE: 1. PROGRAM BooleanFunction; 2. 3. Const 4. N= 5; 5. 6. Type 7. arreglo = array [0..N] of integer; 8. 9. Var 10. i, elem: integer; 11. a: arreglo; 12. 13. Function Pertenece(x: integer; A: arreglo): boolean; 14. Var 15. i: integer; 16. 17. Begin 18. i:= 1; 19. 20. While (i <= N) and (A[i] <> x) do 21. i:= i + 1; 22. 23. Pertenece:= i <= N; 24. End; 25. 26. BEGIN 27. Write(Ingresa ,N, enteros: ); 28. For i:=1 to N do 29. read(a[i]); 30. Writeln; 31. Write(Ingrese el elemento a buscar: ); 32. readln(elem); 33. 34. If pertenece(elem,a) then 35. writeln(El elemento ,elem, pertenece al arreglo.) 36. else 37. writeln(El elemento ,elem, no pertenece al arreglo.); 38. 39. END. Quiero que ustedes mismos estudien este ejemplo hasta que lo comprendan. Verifquenlo a mano si hace falta, eso muchas veces funciona para comprender como funciona un programa y es muchas veces lo que hace falta para encontrar un error que ni con el depurador (debuger) podemos hallar.

Vladimir Rodrguez

86

Programacin estructurada en Pascal


Llamar a un subprograma desde otro subprograma: Esto es realmente sencillo y segn mi consideracin no requiere ni de ejemplificacin, solo una leve explicacin para que lo sepan nada ms, aunque an dar un ejemplito genrico. Es posible llamar a un subprograma desde otro siempre y cuando el subprograma que estamos llamando fue declarado antes que el subprograma desde el que estamos llamando. Veamos lo siguiente: Procedure proc1(parmetros nominales); Begin //Instrucciones; End; Procedure proc2(parmetros nominales); Begin //Instrucciones Proc1(parmetros efectivos); End; Como ven aqu tenemos dos procedimientos, Proc1 y Proc2, el primero declarado antes que el segundo. En el cuerpo de Proc2 vemos una llamada a Proc1. Esto es posible porque Proc1 ya est declarado arriba, de lo contrario el compilador nos dira que no encuentra el identificador especificado. Dado esto no podemos llamar a Proc2 desde Proc1. Esto se aplica tanto para procedimientos como para funciones, y es posible llamar a una funcin desde otra, a un procedimiento desde una funcin, a una funcin desde un procedimiento, etc., en fin, a un subprograma desde otro.

Como habrn visto, hasta el momento hemos usado solo el pasaje de parmetros por valor tanto para funciones como para procedimientos. La prxima seccin de este manual explicar el pasaje de parmetros por referencia. Esto llevar un poco de trabajo para su entendimiento, pero si se esmeran vern que no es tan complicado. Espero que hasta ahora hayan entendido todo. Como ya saben pueden escribirme a mi casilla de correo mstrvladi@hotmail.com para consultar cualquier duda que tengan y yo se las responder a la brevedad. Tambin pueden sugerir ejercicios o sealar errores en el manual, cosas que tal vez resulten inentendibles, etc.

Vladimir Rodrguez

87

Programacin estructurada en Pascal Parmetros: Pasaje por Referencia:


Antes de comenzar con la explicacin en s de lo que significa el pasaje de parmetros por referencia he de dar una leve y sumamente bsica explicacin acerca de lo que en verdad es una variable. Luego me extender un poco hablando de la memoria RAM para que logren comprender esto lo mejor posible. No se hasta que punto saben ustedes de computadoras, pero asumo que tienen un dominio bastante avanzado si se han lanzado a la programacin. Con esto me refiero a que saben usar una PC sin dificultad alguna, navegar en Internet, descargar y subir archivos. Tambin supongo que saben lo que es un disco duro y para qu sirve, qu es la memoria RAM y para qu sirve, cules son los dispositivos de entrada y salida, etc. An as veamos un pantallazo muy general acerca de la memoria RAM, que es lo que nos importa ahora. Todos ustedes deben de haber visto que al obtener un nuevo programa este suele especificar los requerimientos mnimos del equipo para que pueda funcionar. Lo ms importante acerca de estos requerimientos es la velocidad de procesamiento de la CPU, la capacidad de almacenamiento del disco duro y la cantidad de memoria RAM; para los juegos tambin suele indicarse el mnimo requerido de capacidad y velocidad de la GPU (tarjeta grfica). Como deberan saber, la CPU (Central Processing Unit) o Unidad Central de Procesamiento corresponde al cerebro de la computadora y es la que se encarga de procesar absolutamente toda la informacin que se est transfiriendo en el momento. De este modo la CPU enva luego diferentes instrucciones a los diferentes componentes de la computadora para que estos realicen sus propias tareas. Como han visto ahora que saben lo que es programar, una CPU se dedica a seguir instrucciones bien estructuradas. Las sigue paso a paso tal y como son dictadas por los programadores. Por eso decimos que una computadora no es inteligente, es estpida ya que hace exactamente lo que se le dice y nada ms. Claro que existen algoritmos de inteligencia artificial que permiten pensar a una computadora, pero no tengo idea de cmo funcionan y adems no son relevantes aqu. Las instrucciones que sigue la CPU son cargadas en la memoria RAM solo mientras se necesiten all, luego son eliminadas para liberar la memoria y dejar lugar a otras instrucciones. Tambin se libera toda la RAM al apagar el PC. Esta memoria est dividida en celdas que a su vez estn dividas en celdas que representan bits de informacin. En dichas celdas es donde se guardan las variables, las constantes, etc. Dependiendo de la informacin que contenga una variable o algn otro elemento ser la cantidad de celdas de memoria que se necesitarn para almacenarlo. No es lo mismo guardar un entero que un arreglo de enteros, claramente el segundo es mucho ms grande que el primero. Como pueden ver en la imagen, tenemos un pequeo trozo de cdigo Pascal y una representacin de la memoria RAM. En el cdigo Pascal podemos ver la declaracin de una variable entera a que es inicializada con el valor 10. Lo que en realidad estamos haciendo es ocupar una celda de memoria, o parte de ella, con el valor entero 10. Lo que para nosotros representa el identificador a es el nombre de la variable, pero en realidad para la CPU esa es la direccin de la celda de memoria donde se est guardando la informacin de esa variable. Cuando nosotros declaramos constantes o variables lo que estamos haciendo en realidad es guardar celdas de memoria para almacenar su informacin. Los identificadores (nombres) solo contienen la referencia a la celda de memoria donde se guarda la informacin. Es por esto que no podemos duplicar identificadores, sera como decirle al CPU Guarda la informacin de esta variable en tal celda de memoria, y la de esta otra variable tambin all, pero ambas deben ser independientes eh. Por este motivo es bueno que un programa utilice siempre la menor cantidad de variables posible, para que necesite menos memoria RAM para poder ejecutarse. Fjense que normalmente los programas son muy complejos y tienen miles de variables, tipos, constantes y estructuras diferentes. Piensen nada ms en el programa que estn usando ahora para leer este texto si es que lo hacen en su computadora, o piensen en el procesador de texto que yo us para escribirlo. Cuntas variables hay? Adems tambin se carga la interfaz grfica para que nosotros veamos botoncitos, menes e conos, cuadros de texto, etc. Hay miles de estructuras dentro de dicho programa que se dedican a ir verificando si lo que se escribe tiene faltas de ortografa o no, estructuras de bsqueda, de correccin, de numeracin, etc. Podra escribir un nico manual dedicado al anlisis de un procesador de textos avanzado como lo es Microsoft Word u OpenOffice Writer. Cuando nosotros escribimos una expresin de asignacin del tipo x:= y; estamos diciendo: Ve a la celda donde est la informacin de Y y copia esta informacin en la celda donde guardas la de X. . Esto solo copia los contenidos de las celdas de memoria, pero ambas siguen siendo independientes. Lo mismo pasa cuando llamamos a un subprograma y le damos parmetros de entrada, lo que hacemos es copiar el contenido de las celdas de memoria de los parmetros efectivos en los nominales, pero unos siguen siendo independientes de otros. Esto no suceder en el pasaje de parmetros por referencia ya que en realidad no pasaremos los contenidos de las celdas sino la referencia de su ubicacin en la memoria.

Vladimir Rodrguez

88

Programacin estructurada en Pascal


Bien, veamos entonces lo que significa el pasaje de parmetros por referencia. Primero lo explicar tal como es y luego lo detallar con ilustraciones y ejemplos para que puedan comprenderlo bien ya que esto es un tema muy importante para la programacin y lo necesitarn si pretenden lanzarse a aprender un lenguaje ms avanzado que el Pascal. Como ya dije, en el pasaje de parmetros por referencia no copiamos el contenido de una celda de memoria en otra sino que copiamos la referencia de su ubicacin en la memoria. Veamos qu cornos significa esto: Cuando hablo de referencia a una celda de memoria me refiero a su direccin. Cada celda tiene una direccin nica en la memoria, o sea, lo que indica su ubicacin. Imaginen que cada celda de memoria es un hogar diferente disponible para habitar; al igual que en el mundo real, cada hogar tiene una direccin nica. No importa cmo se escribe esa direccin ni como la interpreta la CPU, solo importa que cada celda tiene una nica direccin que la identifica. Si les parece mejor, imaginen que esa direccin es una flecha que le dice a la variable Esa celda de all es donde guardars tu informacin. Veamos varios dibujos ilustrando primero las asignaciones normales (lo que hemos visto hasta ahora) y luego las de pasaje por referencia. Supongan que declaramos tres variables tal como lo ven en la Figura 1. En ese momento se asignarn lugares de memoria para dichas variables pero como no les hemos asignado ningn valor no sabemos qu informacin pueda contener cada celda. Luego, en al Figura 2, le asignamos a cada variable un valor, entonces el programa mirar la flecha de esa variable y asignar ese valor a la celda que le corresponde sustituyndolo por el valor anterior:

Figura 1

Var

x, y: integer; a: char;

Figura 2

X:= 10; Y:= 15; a:= c;

15 ? ? ?

x y a
10 c

x y a

Ahora imaginen que luego de las asignaciones de la Figura 2 realizamos la de la Figura 3:

Figura 3

y:= x;

Como pueden ver all lo nico que hemos hecho fue asignarle a y el valor de x y por lo tanto lo que sucedi fue que se copi el valor que estaba en la celda de x hacia la celda de y. Tambin puede verse que cada celda sigue siendo independiente y cada variable sigue manteniendo su misma celda, o sea, cada flecha sigue apuntando al mismo lugar que antes.

10

x y a

10 c
Vladimir Rodrguez

Eso es lo que no suceder en el pasaje por referencia ya que lo que hacemos en ese caso es cambiar la direccin de las flechas. Es importante notar que las celdas no se guardan en ningn orden especfico, por eso la celda de x est ms abajo que la de y a pesar de que la primera variable se declara antes. Veamos un ejemplo de un procedimiento llamado proc1 con tres parmetros, num1, num2 y letra, a los cuales les pasamos sus valores con el pasaje por valor tal y como lo hemos venido haciendo hasta ahora:

89

Programacin estructurada en Pascal

Figura 4 10 15 c 10 15 c
x Y a num1 num2 letra
Var x, y: integer; a: char; Procedure proc1(num1, num2: integer; letra: char); (. . .) //Bloque del procedimiento. BEGIN x:= 10; y:= 15; a:= c; proc1(x,y,a); END.

Pues bien, veamos lo que ilustra esta figura. Declaramos las variables globales x, y como enteros y a como carcter. El procedimiento tiene los tres parmetros que ya nombre los cuales tambin funcionan como variables (eso ya lo expliqu antes). Al comenzar el programa le asignamos a cada variable global un valor especfico de acuerdo a su tipo y luego llamamos al procedimiento indicando qu valor de cada variable debe asignarse a cada parmetro. Eso lo hacemos al colocar las variables entre parntesis al llamar al procedimiento ya que el orden en que esas se colocan es el que indica cual variable corresponde a cual parmetro. De ese modo copiamos el valor de x a num1, el de y a num2 y el de a a letra. A los efectos de lo que sucede en memoria eso es lo mismo que hacer las siguientes asignaciones: num1:= x; num2:= y; letra:= a;

Ahora veamos el mismo ejemplo pero pasaremos por referencia el valor del parmetro letra, los otros dos seguirn siendo por valor. Aqu podrn apreciar qu es lo que le indica al programa cul parmetro se toma por referencia y cual no. Usar dos figuras para este ejemplo, una para antes de la llamada al procedimiento y otra para luego de la misma:

Vladimir Rodrguez

90

Programacin estructurada en Pascal

Figura 5 10 15 c ? ? ?
x Y a num1 num2 letra
Var x, y: integer; a: char; Procedure proc1(num1, num2: integer; var letra: char); //Bloque del procedimiento. BEGIN x:= 10; y:= 15; a:= c; END.

Vean que el encabezado del procedimiento sigue siendo igual excepto porque usamos la palabra reservada VAR antes de declarar el parmetro letra. Usar esta palabra antes de declarar los parmetros indica que los valores de estos sern tomados por referencia. Ahora veamos lo que sucede luego del llamado al procedimiento:

Figura 6 10 15 c 10 15
x Y a num1 num2 letra
Var x, y: integer; a: char; Procedure proc1(num1, num2: integer; var letra: char); //Bloque del procedimiento. BEGIN x:= 10; y:= 15; a:= c; proc1(x,y,a); END.

Vladimir Rodrguez

91

Programacin estructurada en Pascal


Qu sucedi? Pues bien, como ya dije antes, en el pasaje de parmetros por referencia estamos pasando la direccin de una celda y no su valor, por tanto como el parmetro letra es pasado por referencia le estamos diciendo que tome la misma celda de memoria que a para guardar sus valores. Esto implica que ahora hay dos variables que utilizan la misma celda para almacenarse y por lo tanto si modificamos una modificamos la otra y que apuntan a lo mismo, o sea, si dentro del bloque del procedimiento hacemos una asignacin letra:= z; el valor de la celda que ahora dice c cambiar a z y por lo tanto, a tambin valdr z y no c. Lo mismo si hacemos al revs, imaginen que asignamos a:= h; dentro del procedimiento. El parmetro letra tambin valdr h ya que mira a la misma celda. En simples palabras, a y letra pasan a formar uno mismo, o sea, es como si nombrramos la misma cosa de dos formas diferentes. Da lo mismo si la llamamos a o letra, modifican y responden lo mismo en tanto miren a la misma celda de memoria. Este efecto durar solo dentro del bloque principal del procedimiento. Una vez salgamos de all todo volver a la normalidad. Tal vez piensen que podra haber explicado esto de un modo ms corto, pero cranme que no basta solo con decir En el pasaje de parmetros por referencia el parmetro efectivo y el nominal pasan a ser uno mismo durante toda la ejecucin del subprograma. Esto generar muchas dudas a la hora de trabajar, incluso ahora las tendrn cuando comiencen con los ejercicios. Importante: Declarado un parmetro por referencia solo puede usarse una variable como parmetro efectivo y no un valor especfico. Esto significa que para este procedimiento Procedure proc1(num1, num2: integer; var letra: char); no podemos hacer una llamada como esta: proc1(x,y,10); pero s una proc1(x,5,a); ya que num1 y num2 son parmetros que se toman por valor.

Veamos ahora dos ilustraciones ms. En la Figura 7 vemos lo que sucede si los parmetros num1 y num2 se toman por referencia y letra por valor, y en la Figura 8 vemos lo que sucede si todos son parmetros tomados por referencia:

10 15 c

x Y a num1

Var

Figura 7
x, y: integer; a: char;

Procedure proc1(var num1, num2: integer; letra: char); //Bloque del procedimiento. BEGIN x:= 10; y:= 15; a:= c; proc1(x,y,a); END.

num2 letra

Vladimir Rodrguez

92

Programacin estructurada en Pascal

10 15 c

x Y a num1 num2 letra

Var

Figura 8
x, y: integer; a: char;

Procedure proc1(var num1, num2: integer; letra: char); //Bloque del procedimiento. BEGIN x:= 10; y:= 15; a:= c; proc1(x,y,a); END.

Dado que utilizar pasaje de parmetros por referencia modifica al parmetro efectivo usamos estos como parmetros de entrada/salida a un procedimiento. Esto es muy til ya que a diferencia de una funcin podemos obtener muchos datos de salida en vez de uno solo. NOTA: No es recomendable utilizar el pasaje de parmetros por referencia para las funciones. Con esto quedara abarcado todo lo referente a los subprogramas y por tanto es hora de practicar todo lo que han ledo ya que sin prctica no avanzarn un pelo. Es totalmente imprescindible que los hagan todos o de lo contrario no servir de nada todo lo dado hasta ahora. Los ms importantes son los ltimos, escritos en letra roja los que corresponden a un parcial de facultad. Todo lo dado en las clases es lo que yo les he explicado aqu y los ejercicios que les he puesto, incluso los enlaces de inernet, perteneces a la facultad y por tanto ustedes son totalmente capaces de resolver estos ejercicios habiendo ledo este manual y habindose esforzado en realizar los ejercicios planteados y estudiar los ejemplos que les he puesto.

Ejercicios: Ejercicio 1: Expliquen la diferencia entre un parmetro formal (o nominal) y un parmetro verdadero (o efectivo).

Ejercicio 2: Escriban un procedimiento con solo tres parmetros enteros: a, b y c. El efecto del procedimiento debe ser girar los valores de los parmetros hacia la derecha de manera que, despus de la ejecucin, el valor que originalmente estaba en a quede en b, el que estaba en b quede en c y el que estaba en c quede en a. Ejemplos de entrada: 4 1 7 -12 6 2 Ejemplos de salida: 7 4 1 2 -12 6

Vladimir Rodrguez

93

Programacin estructurada en Pascal


Ejercico 3: Consideren el siguiente programa :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 1. 2. 3. 4. 5. 6.

PROGRAM alcance; Var tum, num, temp: Integer; Procedure Prog (a, b: integer; VAR c: integer); Var reloj: Integer; Begin reloj:= a * b; reloj:= reloj + 1; c:= reloj + a; WriteLn(a, b, c, reloj) End; (*Programa principal*) BEGIN tum:= 1; num:= 2; Prog(tum, num, temp); WriteLn(temp); tum:= 0; num:= 1; Prog(tum, num, temp); WriteLn(temp) END.

Identifiquen la/s variable/s globales del programa principal. Identifiquen la/s variable/s local/es declarada/s en el procedimiento Prog. Identifique los parmetros formales del procedimiento Prog. Determine los parmetros de entrada (de valor) y de salida (por variable). Determine los parmetros por valor verdaderos (efectivos) en la primera invocacin del procedimiento. Determine los parmetros por valor verdaderos (efectivos) en la segunda invocacin del procedimiento. Determine la salida estndar del programa. Cuntas lneas se escribirn?

Ejercicio 4: Dado el siguiente procedimiento

PROCEDURE Prueba (x: Real; y: Integer; VAR z: Real); y las siguientes variables

VAR tiempo : Real; tiempo_i : Integer; Determinen cules de las siguientes invocaciones son correctas. Justifiquen. Prueba( 1, 2.0, tiempo ); Prueba( tiempo_i, 3, tiempo ); Prueba( tiempo_i, 3, 2.0 ); Prueba( 1, 3, tiempo_i ); Prueba( 5 * tiempo_i, round( 7.3 ), tiempo ); (* tiempo_i ya fue inicializada *) Prueba( tiempo, 3, tiempo ); Prueba( Prueba( 5, 33.8, tiempo ), 92, tiempo ); Cules son los errores en las invocaciones incorrectas? Ejercicio 5: Implementen un procedimiento que dado un arreglo de enteros devuelva el valor ms grande y el ndice en que ste ocurre. El largo del arreglo es dado por una constante N global al procedimiento. Ejercicio 6: Escriban una funcin llamada conv que convierta un arreglo de caracteres, cada uno de los cuales contiene un dgito decimal, al entero equivalente.

Vladimir Rodrguez

94

Programacin estructurada en Pascal


Por ejemplo, si el parmetro de entrada es [ `1, `2, `3 ], entonces el entero resultante ser 123. El largo del arreglo es dado por una constante N global a la funcin.

Ejercicio 7: Implementen una funcin que dados 2 arreglos de caracteres, determine si el primero es prefijo del segundo. Luego reescriban el Ejercicio 2 de la pgina 63 utilizando esta funcin. En caso de que la cadena ms corta pertenezca a la ms larga, despliegue en la salida estndar la posicin en que comienza la coincidencia. Tomando el primer ejemplo dado en la letra de dicho ejercicio, la salida sera: El texto 'tor' se encuentra dentro del texto 'totora' ( posicin de comienzo: 3 ). En caso de que no haya coincidencia, el mensaje deber ser el mismo que en el ejercicio 2 de la pgina 63.

Ejercicio 8: Dado el siguiente programa: PROGRAM principal (input, output); VAR a, b : Integer; PROCEDURE a1 (VAR x : Real); VAR c : char; PROCEDURE a2 (y : char); VAR d : Integer; BEGIN . . . END; BEGIN . . . END; PROCEDURE b1; VAR e : Integer; BEGIN . . . END; BEGIN . . . END; Indiquen las variables a las que se puede hacer referencia dentro del alcance del procedimiento a2, las que se pueden referenciar dentro de a1, las que se pueden referenciar dentro de b1 y las variables globales.

Ejercicio 9: Determinen la salida del siguiente programa si se obtiene de la entrada estndar el entero 4 (elegir la opcin a, b, c o d). PROGRAM Ppal (input, output); VAR x : Integer; PROCEDURE a (VAR y : Integer); BEGIN y := y * 2; END; PROCEDURE b (x : Integer); BEGIN x := x + 5;

Vladimir Rodrguez

95

Programacin estructurada en Pascal


END; BEGIN ReadLn (x); b (x); WriteLn (x); a (x); WriteLn (x); END. a 4 8 b4 9 c9 18 d9 8

Ejercicio 10: Determinen la salida del siguiente programa: PROGRAM Detectar (input, output); VAR a, b, c, d : Integer; PROCEDURE pal (y: Integer; VAR z: Integer); VAR c : Integer; BEGIN b := y * z; c := b + z; y := y + 1; z := z * (z + 1); WriteLn (b:3, c:3, y:3, z:3) END; BEGIN a := 2; c := 3; d := 5; pal (c, WriteLn b := 4; pal (b, WriteLn END.

d); (a:3, b:3, c:3, d:3); a); (a:3, b:3, c:3, d:3)

El simbolo - representa el salto de lnea. A: 15 20 4 30- 2 15 4 30- 9 10 9 6- 6 9 4 30 B: 15 20 4 30- 2 15 4 5- 9 10 9 6- 2 9 4 5 C: 15 20 4 30- 2 15 3 30- 8 10 5 6- 6 8 3 30 D: 15 20 4 30- 2 15 3 5- 8 10 5 3- 2 8 3 5

Ejercicio 11: Indiquen cual sera la salida del siguiente programa suponiendo que como entrada se le proporciona el ltimo dgito de su nmero de cdula de identidad. Por ejemplo, si su nmero de cdula es el 1.234.567-8, entonces el nmero que se ingresa es el 7. Program Ej1 (input,output); var z: integer; function f (y : integer) : boolean; begin z := z + y; f := y mod 2 = 0 end; procedure a (var y : integer);

Vladimir Rodrguez

96

Programacin estructurada en Pascal


begin y := 2 * y; end; procedure b (var z : integer); begin z := z + 5; end; begin readln(z); if f(z) then a(z) else b(z); writeln('Salida = ', z) end.

Ejercicio 12: Indique cual sera la salida del siguiente programa suponiendo que como entrada se le proporciona el ltimo dgito de su nmero de cdula de identidad. Por ejemplo, si su nmero de cdula es el 1.234.567-8, entonces el nmero que se ingresa es el 7. El orden de evaluacion de las expresiones numericas depende de cada compilador. En este caso, asuma que ese orden es de izquierda a derecha. program jul2002 (input,output); var z: integer; function g (var x: integer):integer; begin x := x + 1; z := z + 1; writeln('Salida en g1:',x + z); g := x + z end; function f (x: integer; var y: integer): integer; function g(x: integer): integer; begin x := x + 1; writeln('Salida en g2:',x + z); g := x + z end; begin x := x + 1; z := z + x - y + 2; if x mod 2 = 0 then y := y + 1 else y := y - 1; x := g(x) + y; writeln('Salida en f:',x); f := x end; procedure p (var x,y: integer); begin y := f(x,y) + z; y := y + g(x) + x; x := x + 1; writeln('Salida en p:',y) end; begin readln(z); p(z,z); writeln('Salida final:',z + 1); end.

Vladimir Rodrguez

97

Programacin estructurada en Pascal

Vladimir Rodrguez

98

Programacin estructurada en Pascal

QUINTA PARTE

Enumerados Registros con y sin variante Arreglo con tope

Vladimir Rodrguez

99

Programacin estructurada en Pascal Introduccin:


Volvemos una vez ms a los tipos definidos por el programador. Hasta ahora trabajamos con los Subrangos, que podan tomar valores consecutivos dentro de un rango especfico contenido en un rango mayor; y los Arreglos, que correspondan con tablas de datos de un mismo tipo. Dichas tablas podan tener una dimensin, dos, tres o muchas ms. Luego de eso cambiamos de tema para pasar a los Procedimientos y las Funciones, que correspondan con pequeos programas dentro del programa principal cuya funcin era realizar una tarea especfica. Ahora hace falta terminar de ver los tipos que podemos definir nosotros mismos como programadores, y nos quedan tres: Enumerados, Conjuntos (casi no trabajaremos con ellos) y Registros. Lo verdaderamente importante aqu son los Registros ya que estos son capaces de almacenar varios datos diferentes y de diferentes tipos cada uno, pero esto ya lo ampliaremos en su momento.

Vladimir Rodrguez

100

Programacin estructurada en Pascal Enumerados:


Los Enumerados, tal como su nombre lo indica, son enumeraciones de ciertos elementos especficos y que generalmente corresponden a un mismo grupo de calificacin. Por ejemplo, los das de la semana corresponden todos a un mismo grupo (das de la semana); los meses del ao tambin son un grupo especfico, y as con muchas otras cosas que se nos pueden ocurrir. Bsicamente un enumerado es un conjunto de elementos que nosotros definiremos uno a uno. Realmente no resultar difcil trabajar con este tipo de datos. Veamos primero su declaracin: Type diasSemana=(domingo, lunes, martes, miercoles, jueves, viernes, sabado); Mes= (enero, febrero, marzo, abril, mayo, junio, julio, agosto, setiembre, octubre, noviembre, diciembre); puntoCardinal= (norte, sur, oeste, este); Utilizamos primero la palabra Type y luego, al igual que antes, le damos un nombre al tipo seguido de un signo de igual. Luego colocamos entre parntesis y separados por comas cada elemento del enumerado. De este modo tenemos all uno que contiene todos los das de la semana, otro con todos los meses del ao y otro con los cuatro puntos cardinales. La declaracin genrica de un tipo enumerado sera as: Type nombreDelTipo= (elemento1, ,elementoN); donde cada elemento dentro de los parntesis corresponde a un identificador cualquiera. As, los elementos de los enumerados, pueden llamarse de cualquier manera pero jams repetirse, jams pueden comenzar con nmeros o caracteres especiales ni contener espacios; como ya dije, son identificadores y por ende han de cumplir las mismas reglas que estos. Visto de esta manera no resulta muy sencillo hallarle una utilidad a los enumerados, sin embargo podremos ver que s la tienen cuando usemos registros. Por este motivo ahora veremos solo aspectos generales de este tipo de datos para luego poder aplicarlos realemente con lo registros. Para empezar, cada elemento que asignamos a un enumerado tiene un ordinal de acuerdo a la posicin en la que est nombrado comenzando a contar desde el nmero 0. De este modo para el tipo diasSemana tendramos los siguientes ordinales: ord(domingo)= 0 ord(lunes)= 1 ord(viernes)= 5 ord(sabado)= 6 De modo inverso podemos obtener un elemento de un enumerado dado su ordinal. Para el tipo diasSemana esto sera as: diasSemana(0)= domingo diasSemana(3)= miercoles Aplicando estas dos propiedades a los tipos Mes y puntoCardinal podramos tener lo siguiente: Mes(0)= enero Mes(11)= diciembre ord(octubre)= 9 puntoCardinal(0)= norte puntoCardinal(3)= este ord(sur)= 1

Recuerden siempre que la funcin ORD devuelve un valor del tipo integer. Ahora dganme cul sera la salida que obtendramos de las siguientes sentencias si pertenecieran a un programa donde estn declarados los enumerados anteriores: writeln(ord(Mes(0))); writeln(puntoCardinal(ord(domingo))); Es sumamente importante que al intentar obtener un elemento de un enumerado dado por su ordinal jams utilicemos un entero que est por fuera del rango de elementos del enumerado. Esto significa que, por ejemplo, para el tipo diasSemana no escribamos algo como esto: diasSemana(7), diasSemana(-1),

Vladimir Rodrguez

101

Programacin estructurada en Pascal


diasSemana(1.5). Como ven, en el primer caso estamos yndonos un lugar fuera del enumerado, en el segundo caso estamos pidiendo el elemento de una ubicacin negativa la cual jams existir y en el tercer caso pasamos como parmetro un real cuando solo se admiten enteros, dato este ltimo que no les haba dicho.

Read y Write con enumerados: Como primera cosa les digo que... NO ES POSIBLE HACER READ Y/O WRITE con los enumerados. Esto significa que, declarada una variable de un tipo enumerado, no podemos incluir esta dentro de un procedimiento READ, READLN, WRITE o WRITELN. Por ejemplo, para los enumerados anteriores, el siguiente fragmento de cdigo estara mal: Type diasSemana=(domingo, lunes, martes, miercoles, jueves, viernes, sabado); mesAo= (enero, febrero, marzo, abril, mayo, junio, julio, agosto, setiembre, octubre, noviembre, diciembre); puntoCardinal= (norte, sur, oeste, este); Var dia: diasSemana; mes: mesAo; punto: puntoCardinal; BEGIN read(dia); mes:= enero; writeln(' ',enero); punto:= sur; writeln('El da ',dia,' de ',mes,' fuimos al ',punto,'.'); END. Si han entendido lo que he hablado de enumerados hasta ahora podrn darse cuenta rpidamente de que los errores en este cdigo estn dados por el uso de variables de tipos enumerados en procedimientos READ y WRITE. Las asignaciones s son correctas. Noten que para inicializar una variable de tipo enumerado con un valor especfico lo hacemos como con cualquier otra, o sea, damos el nombre de la variable seguido del smbolo de asignacin := y luego el valor que le queremos dar escrito tal cual lo nombramos nosotros al incluirlo en el enumerado.

Comparaciones con enumerados: Segn el orden de enumeracin en que estn dados los elementos de un enumerado tenemos los mismos smbolos de comparacin que para los nmeros: < <= = >= > <> Menor que Menor o igual que Igual que Mayor o igual que Mayor que Distinto que

Por ejemplo, para el tipo puntoCardinal= (norte, sur, oeste, este) tenemos que norte<sur ya que el primero est en la posicin 0 y el segundo en la posicin 1. Lo mismo si la comparacin fuera de diferencia: norte<>sur. Supongo que no debera decir que no es posible comparar variables de tipos enumerados diferentes ya que seran variables de distintos tipos, o sea, para nuestro fragmento de cdigo anterior no sera posible comparar la variable dia con la variable mes ya que son de tipos diferentes, una del tipo diasSemana y la otra del tipo mesAo. Como debera resultar obvio ya, los tipos enumerados son tipos ordinales, o sea, tienen una cantidad finita de elementos y dado cualquiera de ellos es posible saber cul es el anterior y cual es el siguiente al mismo. Por lo tanto para estos tipos de datos podemos utilizar las funciones predefinidas de Pascal succ y pred, la primera para obtener el sucesor de un elemento siempre y cuando no nos estemos refiriendo al ltimo, y la segunda para obtener el

Vladimir Rodrguez

102

Programacin estructurada en Pascal


predecesor de un elemento siempre y cuando no nos estemos refiriendo al primero. Volviendo a ejemplificar con los tres tipos enumerados definidos al inicio de esta seccin tendramos lo siguiente: succ(lunes)= martes pred(noviembre)= octubre succ(este) //No tiene sucesor, es el ltimo elemento. pred(domingo) //No tiene predecesor, es el primero. En la mayora de los ejemplos que he dado aqu acerca de estas dos funciones, de las comparaciones y de la utilizacin de ordinales para enumerados he utilizado directamente los elementos del enumerado, o sea, si miran aqu arriba hay cosas como succ(lunes)= martes, cuando en general lo que se usa son variables del tipo enumerado. Con esto quiero decir que si, por ejemplo tuviramos una variable declarada como la siguiente Var dia: diasSemana; BEGIN dia:= lunes; END. podramos utilizar a dicha variable dentro de las funciones de sucesor y predecesor as como tambin en comparaciones y la funcin ORD. Por ejemplo: succ(dia)= martes; pred(dia) //No tiene sucesor. ord(dia)= 1 //Es el segundo elemento del enumerado. dia<>martes //Es verdadero ya que la variable dia es igual a lunes. Bien, ahora veamos un pequeo ejemplo de programa en el cual tendremos un enumerado con los das de la semana, otro con los meses del ao y un subrango de enteros que ir desde el nmero 1 al 31. El usuario elegir un da de la semana, la fecha correspondiente al mismo da y el mes, tras lo cual el programa desplegar la fecha en formato DA/MES/AO y en formato de oracin. Vemoslo:
1.PROGRAM enumerados; 2. 3.Type 4. diasSemana= (domingo, lunes, martes, miercoles, jueves, viernes, sabado); 5. diasMes= 1..31; 6. mesAnio= (enero, febrero, marzo, abril, mayo, junio, julio, agosto, 7. setiembre, octubre, noviembre, diciembre); 8. 9.Var 10. dia: diasSemana; //Guarda un da de la semana. 11. fecha: diasMes; //Guarda un da del mes. 12. mes: mesAnio; //Guarda un mes del ao 13. anio, aux: integer; //anio guarda el ao, aux es para leer enteros. 14. 15.BEGIN 16.{Pedimos al usuario que ingrese los datos----------------------------------} 17. //Pedimos el ingreso del ao en cuestin. 18. write('Ingresa el ao: '); 19. readln(anio); 20. 21. //Pedimos el ingreso del nmero del mes del ao. 22. write('Ingresa un nmero correspondiente a un mes del ao (1-12): '); 23. readln(aux); 24. mes:= mesAnio(aux - 1); 25. 26. //Pedimos el ingreso del nmero del da de la semana. 27. write('Ingresa un nmero correspondiente a un da de la semana (1-7): '); 28. readln(aux); 29. dia:= diasSemana(aux - 1); 30. 31. //Pedimos el ingreso del nmero de un da del mes. 32. write('Ingresa un nmero correspondiente a una fecha del mes (1-31): '); 33. readln(fecha); 34. 35. writeln; 36. 37.{Escribimos la fecha en formato DIA/MES/AO.-------------------------------}

Vladimir Rodrguez

103

Programacin estructurada en Pascal


38. 39. //Escribimos la fecha en formato DD/MM/AAAA. writeln('La fecha ingresada DIA/MES/AO es: ',fecha,'/',ord(mes+1,'/', anio,'.');

40. 41.{Escribimos la fecha en formato de oracin---------------------------------} 42. //Primero escribimos el da. 43. Case dia of 44. domingo: write('Domingo '); 45. lunes: write('Lunes '); 46. martes: write('Martes '); 47. miercoles: write('Mircoles '); 48. jueves: write('Jueves '); 49. viernes: write('Viernes '); 50. sabado: write('Sbado '); 51. End; 52. 53. //Ahora escribimos la fecha del mes. 54. write(fecha,' de '); 55. 56. //Ahora escribimos el mes. 57. Case mes of 58. enero: write('Enero del ao '); 59. febrero: write('Febrero del ao '); 60. marzo: write('Marzo del ao '); 61. abril: write('Abril del ao '); 62. mayo: write('Mayo del ao '); 63. junio: write('Junio del ao '); 64. agosto: write('Agosto del ao '); 65. setiembre: write('Setiembre del ao '); 66. octubre: write('Octubre del ao '); 67. noviembre: write('Noviembre del ao '); 68. diciembre: write('Diciembre del ao '); 69. End; 70. 71. //Escrbimos el ao. 72. write(anio,'.'); 73.END.

Analicemos un poco este cdigo desde el comienzo de su bloque principal. Primero pedimos al usuario que ingrese un ao y lo leemos como entero. Luego en la lnea 22 le indicamos que ingrese un nmero entre 1 y 12 para indicar un mes del ao, y en la lnea siguiente le asignamos a la variable mes el elemento cuyo ordinal es igual al valor indicado por el usuario menos 1. Esta resta se debe a que los meses del enumerado estn numerados del 0 al 11 y el usuario ingresa nmeros del 1 al 12. Aplicamos el mismo procedimiento para inicializar la variable dia. En ambos casos usamos una variable auxiliar llamada aux para leer los enteros ingresados por el usuario. Como ltimo dato pedimos que se ingrese la fecha del da, o sea, a qu da del mes nos estamos refiriendo y leemos este como un entero guardndolo en la variable fecha. En la lnea 39 escribimos la fecha en formato DD/MM/AAAA. Noten que en el procedimiento WRITELN de dicha lnea, para escribir el nmero del mes al que nos referimos escribimos el ordinal de la variable mes volvindole a sumar 1. Esto ya deberan entenderlo. Ahora comienza lo interesante ya que utilizamos dos veces la funcin CASE. En el CASE de la lnea 43 estamos diciendo: Si la variable da es igual al valor domingo entonces escribe 'Domingo ', sino, si es igual al valor lunes entonces escribe 'Lunes ',.... Esta funcin es equivalente a una anidacin de IF como la que sigue: If dia=domingo then write('Domingo ') else if dia=lunes then write('Lunes ') else if dia=martes then write('Martes ')... Si entendieron eso deberan ser capaces de entender el CASE de la lnea 57 ya que funciona exactamente igual. Como siempre les digo que ante cualquier duda o inquietud que tengan as como ante cualquier sugerencia escrbanme a mstrvladi@hotmail.com y les responder a la brevedad. Ahora entretnganse con algunos ejercicios acerca de los enumerados.

Vladimir Rodrguez

104

Programacin estructurada en Pascal


Ejercicios Ejercicio 1: Consideren la siguiente declaracin: TYPE color = (rojo, blanco, azul, purpura); VAR coloracion : color; Determinen cules de los siguientes fragmentos de cdigo son vlidos justificando la respuesta:
a) Read (rojo); WriteLn (rojo); d) coloracion := blanco; CASE coloracion OF rojo : WriteLn ('rojo'); blanco : WriteLn ('blanco'); azul : WriteLn ('azul'); purpura: WriteLn ('purpura') END; coloracion := azul; CASE coloracion OF rojo : WriteLn (rojo); blanco : WriteLn (blanco); azul : WriteLn (azul); purpura: WriteLn (purpura) END; IF coloracion = azul THEN WriteLn ('azul') ELSE WriteLn ('no azul')

b)

Read (coloracion); Write (coloracion);

e)

c)

coloracion := blanco; WriteLn (coloracion);

f)

Ejercicio 2: Determinen cuales de las siguientes declaraciones son vlidas: a) TYPE letra = ('X', 'Y', 'Z'); b) TYPE lenguaje = (Pascal, Fortran, Basic); c) TYPE materias = (matematicas, historia, computacion, biologia); carrera = (matematicas, computacion); d)TYPE estado = (residente, ciudadano, extranjero); nacionalidad = (americano, europeo, africano, asiatico, otra); e) TYPE codigo = (1, 2, 3, 4, 5); f) TYPE codigo = (c1, c2, c3, c4, c5); g)TYPE estado = (soltera, casada, comprometida, divorciada); VAR type : estado; h) TYPE ciudad = (Paysandu, SanJose, Tacuarembo, Canelones); VAR ciudad : type;

i) VAR ciudad : (Rivera, Salto, Soriano, Rocha); j) PROCEDURE encontrar (VAR ciudad : (Minas, Florida, Flores)); k) TYPE trabajo = (obrero, oficinista, indefinido); . . . PROCEDURE buscar (VAR empleo : trabajo);

Vladimir Rodrguez

105

Programacin estructurada en Pascal


Ejercicio 3: Es posible definir subrangos de enumerados ya que estos ltimos corresponden a un tipo ordinal. Examinen estas declaraciones: TYPE tipodia = (Lunes, Martes, Miercoles, Jueves, Viernes, Sabado, Domingo); VAR dia : tipodia; laborable : Lunes..Viernes; finsemana : Sabado..Domingo; Indiquen cul de las siguientes afirmaciones es correcta: Se producir un error de ejecucin si se asigna el valor Martes a findesemana Se producir un error de ejecucin si se asigna el valor Viernes a laborable.

Ejercicio 4: Examinen la siguiente definicin : TYPE raro = (gugol, nudol, brudol, cudol, zudol, budol); Determinen el valor de las siguientes expresiones:

1. 2. 3. 4. 5. 6.

ord (gugol) ord (zudol) succ (brudol) succ (budol) pred (gugol) ord (succ (zudol))

Ejercicio 5: Obtengan el valor de las siguientes expresiones:

1. 2. 3. 4.

ord ('7') - ord ('0') ord ('1') - ord ('1') chr (3 + ord ('0')) chr (0 + ord ('0'))

Ejercicio 6:: Examinen la siguiente declaracin: TYPE vocal = (a, e, i, o, u); VAR letra : vocal; uncar : char; Determinen si se ejecutar sin error el siguiente cdigo en PASCAL:
letra := a; WHILE letra <= u DO BEGIN Read (uncar); WriteLn (`El caracter capturado es ', uncar); letra := succ (letra) END letra := u; REPEAT Read (uncar); WriteLn (`El caracter capturado es ', uncar); letra := pred (letra) UNTIL letra = a

Vladimir Rodrguez

106

Programacin estructurada en Pascal Registros:


Los tipos de datos que hemos visto hasta ahora han podido ser primitivos (char, integer, real, boolean) o estructurados (subrangos, arreglos, enumerados). Los tres tipos estructurados que vimos son homogneos, o sea, que todos los datos que contienen son de un mismo tipo. Por ejemplo, en un arreglo todas las celdas contienen datos de un mismo tipo, ya sean enteros, reales, u otro tipo definidos por ustedes mismos. Un subrango no es ms que un intervalo ms pequeo dentro de un conjunto de elementos mayor, pero sigue contiendo todos sus elementos de un mismo tipo. Aqu es donde los registros se diferencian de todos los dems tipos ya que pueden contener muchos datos y todos de diferentes tipos. Por ejemplo, podramos tener un registro que contenga caracteres, enteros, reales, cadenas, arreglos y mucho ms. Para ser un poco ms especficos, podramos crear un registro que dada una persona contenga su nombre, apellido, edad, documento de identidad, direccin entre muchas otras cosas.

Declaracin: Bien, primero les dir como se declara genricamente un registro, luego veremos un ejemplo de programa donde guardaremos datos de dos personas, primero sin usar registros y luego usndolos. Type NombreDelRegistro= record campo1: tipo; campo2: tipo; . . . campoN: tipo; End; Como estamos hablando de un tipo resulta obvio que declararemos un registro debajo de la palabra TYPE. Al igual que a los dems tipos definidos por ustedes mismos debemos darle un nombre seguido del signo de igual y luego utilizamos la palabra reservada RECORD (registro en ingls). Despus definimos cada uno de los campos que contendr tal como si fueran variables (en efecto eso son), o sea, le damos un nombre seguido por dos puntos y luego le asignamos un tipo cualquiera recordando que si usaremos uno definido por nosotros mismos debemos haber declarado este antes. Veamos un ejemplo de declaracin de un registro llamado ESTUDIANTE en el cual guardaremos el nombre de un estudiante, su edad, su documento de identidad y el grado que cursa: Type Grados= (primero, segundo, tercero, cuarto, quinto, sexto); Estudiante= record nombre: string; edad, documento: integer; grado: Grados; End; Como ven primero tenemos un tipo llamado GRADOS que no es ms que un enumerado de los grados posibles que un estudiante puede cursar. Nuestro registro contiene cuatro campos (variables), una del tipo string, dos del tipo integer y una ltima del tipo grados, el cual fue declarado previamente por nosotros mismos. Ahora veamos los dos ejemplos de los que habl para ver cmo funcionan los registros. En el siguiente programa guardaremos el nombre, la edad, el documento de identidad y el grado de dos estudiantes distintos. Todos estos datos los asignaremos nosotros manualmente internamente en el programa, o sea, no haremos READ de nada, simplemente le daremos valores a nuestras variables y ya, como si nuestros estudiantes vinieran precargados en el programa: 1. PROGRAM Reg1; 2. 3. TYPE 4. Grados= (primero, segundo, tercero, cuarto, quinto, sexto); 5. 6. VAR 7. NombreEstudiante1, NombreEstudiante2: String; 8. EdadEstudiante1, EdadEstudiante2: Integer; 9. DocumentoEstudiante1, DocumentoEstudiante2: Integer;

Vladimir Rodrguez

107

Programacin estructurada en Pascal


10. GradoEstudiante1, GradoEstudiante2: Grados; 11. 12. BEGIN 13. NombreEstudiante1:= 'Fulano de Tal'; 14. EdadEstudiante1:= 16; 15. DocumentoEstudiante1:= 12345; 16. GradoEstudiante1:= cuarto; 17. 18. NombreEstudiante2:= 'Mengano'; 19. EdadEstudiante2:= 18; 20. DocumentoEstudiante2:= 16543; 21. GradoEstudiante2:= sexto; 22. END. Muy bien, este programa no representa ningn tipo de dificultad para ustedes, simplemente declaramos variables y las inicializamos con valores adecuados a su tipo. Tal vez debo aclarar por qu en las lneas 8 y 9 declar cuatro variables integer cuando podra haber usado una sola lnea. Simplemente para separar las variables que se corresponden con la edad a las que se corresponden con los documentos de identidad. Este programa sera mejor si obtuviera los datos de la entrada estndar, sin embargo eso solo es utilizar READ en cada lnea y ya. Ustedes mismos pueden hacerlo si quieren. Ahora veamos el mismo programa pero usando un registro: 1. PROGRAM Reg1; 2. 3. TYPE 4. Grados= (primero, segundo, tercero, cuarto, quinto, sexto); 5. 6. Estudiante= RECORD 7. Nombre: String; 8. Edad, Documento: Integer; 9. Grado: Grados; 10. END; 11. 12. VAR 13. Est1, Est2: Estudiante; 14. 15. BEGIN 16. Est1.Nombre:= 'Fulano de Tal'; 17. Est1.Edad:= 16; 18. Est1.Documento:= 12345; 19. Est1.Grado:= cuarto; 20. 21. Est2.Nombre:= 'Mengano'; 22. Est2.Edad:= 18; 23. Est2.Documento:= 16543; 24. Est2.Grado:= sexto; 25. END. Bien. Como ven, luego del tipo Grados he declarado el tipo Estudiante que es un registro. Es el mismo que us como primer ejemplo. Dicho registro tiene cuatro campos que funcionan tal cual las variables que ya conocen y se declaran de la misma manera. Como el registro es un tipo creado por nosotros mismos, debemos declarar variables de ese tipo para poder usarlo. Eso hice en la lnea 13 de nuestro programa, declar las variables Est1 y Est2 del tipo Estudiante. Cada una de estas variables contiene a las otras cuatro dentro. De este modo tendremos una variable Nombre, una Edad, una Documento, y una Grados para Est1 as como otras cuatro para Est2. Si queremos acceder a la variable Nombre de Est1 lo hacemos mediante la notacin Est1.Nombre. As con todas las dems. De forma genrica, si tengo un registro genrico como el siguiente MiRegistro= RECORD Campo1: Tipo1; Campo2: Tipo2; . . . CampoN: TipoN; END; y luego declaro una variable MiVariable: MiRegistro; , o sea, una variable llamada MiVariable del tipo MiRegistro, para acceder al Campo1 escribo MiVariable.Campo1, lo mismo si quiero acceder al Campo2. O sea, para acceder al campo nmero I, si I es un nmero entre 1 y N, escribo MiVariable.CampoI.

Vladimir Rodrguez

108

Programacin estructurada en Pascal


Los campos de un registro son variables comunes y corrientes y por tanto todo lo que aplicamos a estas se aplica a dichos campos.

Una estructura compleja: Teniendo los registros podemos crear estructuras muy complejas. Simplemente citar un ejemplo para que les quede ya que lo necesitarn para trabajar en lo que se viene. Supongan las siguiente declaracin TYPE Registro= Record Nombre: String; Documento: Integer; Edad: Integer; End; ListaRegistro= Array[1..7] of Registro; VAR MiLista: ListaRegistro; Como pueden observar simplemente he declarado un registro de tres campos y luego un arreglo de siete celdas donde cada una corresponde al registro. Si lo dibujara podramos tener algo as: MiLista Nombre Documento Edad 4

Nombre Documento Edad 1

Nombre Documento Edad 2

Nombre Documento Edad 3

Nombre Documento Edad 5

Nombre Documento Edad 6

Nombre Documento Edad 7

Si cada celda es un registro, entonces para acceder al campo Nombre de la celda nmero 1 tendramos lo siguiente: MiLista[1].Nombre Recuerden que cada celda de un arreglo es como una variable del tipo del arreglo, por lo tanto, cada celda de este arreglo es del tipo Registro por lo cual funciona como tal. Espero que este simple ejemplo les sirva para visualizar esto. Ahora les propongo un ejercicio para comprender mejor lo bsico de los registros para luego continuar con un programa ms complejo: Ejercicio 1: Determinen cules de las siguientes definiciones de registro son vlidas: a) TYPE estado = RECORD nombre : ARRAY[1..30] OF CHAR; edad : 0..120; sexo : (Fem, Masc); b) TYPE ejemplo = RECORD prueba : 0..100; final : 'A'..'F'; orden : 1..100 END; c) TYPE franco = RECORD prueba : 0..100; examen : 0..10; prueba : 0..100 END;

Vladimir Rodrguez

109

Programacin estructurada en Pascal


d) TYPE califs = RECORD nombre, direccion : ARRAY[1..30] OF CHAR; prueba, examen : 0..100; tipoest : (flojo, trabajador, puntual, impuntual) END;

Ejercicio 2 Programa Complejo: En pos de comprender realmente lo que hemos aprendido hasta ahora, les propondr ir trabajando gradualmente en el programa que describir a continuacin. Su dificultad no se comparar con la de Master Mind, sin embargo ser de gran utilidad trabajar con l. Lo programaremos de forma sencilla, o mejor dicho, lo programarn de forma sencilla para luego ir agregando cosas. De este modo vern, adems de lo que refiere a los temas en s, lo complicado que puede resultar agregar cosas a un programa ya escrito. Por este motivo y por otros ms, yo les ir marcando ciertas estructuras que debern utilizar obligatoriamente ms las que ustedes mismos deseen agregar, de modo que todo sea bastante ms legible que si se hace a lo bruto. Vamos a ello: BASE DE PRODUCTOS Parte 1 Comenzaremos a armar algo as como una base de datos de un comercio pequeo. Dicho comercio tiene a su disposicin elementos que nicamente pueden corresponderse con las siguientes categoras: Comestibles, Frutas y Verduras, Higiene del hogar e Higiene personal. Como ven son solo cuatro. Asimismo, para cada elemento tenemos los siguientes datos que deseamos almacenar: Nombre: Simplemente una palabra que identifique al producto. ID: Un nmero que es nico para cada producto y lo identifica entre los dems. Stock: Qu cantidad de este producto tenemos a disposicin. Precio: Cuanto vale el producto. Categora: A cual de las cuatro categoras anteriores corresponde el producto. Para comenzar supondremos que el comercio tiene nicamente cinco productos a la venta, ni ms ni menos, y que no agregar ni quitar ninguno. Nuestro programa almacenar los datos de cada producto en un arreglo de cinco celdas, una para cada producto, cada una de las cuales almacenar todos los datos mencionados anteriormente. Los datos de cada producto sern ingresados mediante la entrada estndar por un usuario. Asumiremos para todos los casos que los datos ingresados son correctos, o sea que: ID es un nmero entero positivo y que no se repetir para ningn producto, que stock es un entero positivo o 0, que precio es un real positivo y que categora se corresponde con alguna de las anteriores. De este modo tendremos las siguientes declaraciones obligatorias: Const N= 5; Type Categorias= (comestibles, frutas_verduras, higiene_h, higiene_p); TNaturales= 1..MAXINT; Elemento= Record Nombre: String; Stock: TNaturales; Precio: Real; Categoria: Categorias; ID: TNaturales; End; Productos= Array[1..N] of Elemento; Al iniciar nuestro programa debe mostrarnos un men como el siguiente: MEN PRINCIPAL: 1) 2) 3) 4) Ingresar datos de productos. Ver lista de productos. Modificar productos. Vender.

Vladimir Rodrguez

110

Programacin estructurada en Pascal


5) 6) Buscar. Salir.

Opcin: Para el Men Principal usaremos un procedimiento cuya firma ser la siguiente: PROCEDURE MenuPrincipal(VAR listaProductos: Productos); Luego entendern mejor el funcionamiento de esto, ya que para cada men tendremos un procedimiento distinto que ser llamado por el procedimiento MenuPrincipal. El nico parmetro all presente define a nuestra lista de productos, o sea, nuestro arreglos de 5 celdas. Veamos cada men por separado y su declaracin:

1)

Ingresar datos de productos: Este men nos pedir que ingresemos los datos de todos los productos en nuestro arreglo (lista) sin importar si ya haban datos o no, o sea, sobrescribiremos los datos existentes. Al seleccionar esta opcin veremos una pantalla como la siguiente:

|-----------Producto 1-----------| ID >> 1 Nombre >> Azcar Stock >> 10 Precio >> 50,5 Categoras: (1) (2) (3) (4)

Comestibles Frutas y verduras Higiene del hogar Higiene personal

Ingrese la opcin deseada >> 1 All pueden apreciar en negro lo escrito por el programa y en azul lo que ingresa el usuario. Cada opcin aparecer a medida que ingresamos la anterior, o sea, una vez ingresemos el valor de ID y presionemos ENTER, veremos la opcin de ingreso de Nombre. All ven el orden en el que se ingresan los datos. Como las categoras fueron declaradas como un enumerado y estos no pueden leerse desde la entrada estndar, debemos dar una lista de opciones a seleccionar por el usuario y luego en base a esta debemos asignar nosotros mismos el valor de la categora. Si continuramos ingresando datos tendramos algo como esto: |-----------Producto 1-----------| ID >> 1 Nombre >> Azcar Stock >> 10 Precio >> 50,5 Categoras: (1) (2) (3) (4)

Comestibles Frutas y verduras Higiene del hogar Higiene personal

Ingrese la opcin deseada >> 1 |-----------Producto 2-----------| ID >> 2 Nombre >> Harina Stock >> 10 Precio >> 42,5 Categoras: (1) (2) (3) (4)

Comestibles Frutas y verduras Higiene del hogar Higiene personal

Ingrese la opcin deseada >> 1

Vladimir Rodrguez

111

Programacin estructurada en Pascal


|-----------Producto 3-----------| ID >> 3 Nombre >> Desodorante Stock >> 10 Precio >> 89,90 Categoras: (1) Comestibles (2) Frutas y verduras (3) Higiene del hogar (4) Higiene personal Ingrese la opcin deseada >> 4 Y podramos continuar as con los dos productos restantes. Para el ingreso de estos datos usaremos un procedimiento como el siguiente: PROCEDURE IngresoProducto(VAR listaProductos: Productos; indice: integer); Donde indice indicar la posicin en el arreglo listaProductos en la que debe agregarse el producto. Este procedimiento lee directamente desde la entrada estndar por lo cual ser l quin muestre las salidas que se ven en los ejemplos. Tengan en cuenta que este procedimiento ingresa de a un producto en la lista en un lugar deterinado de la misma. La opcin 1 del men modifica toda la lista; ustedes deben implementar eso usando este procedimiento. Al terminar de ingresar todos los datos veremos el mensaje Presione ENTER para volver al men principal... 2) Ver lista de Productos: Este men nos mostrar en pantalla las siguientes opciones:

Ver lista de productos: 0) 1) 2) 3) 4) Ver todos Comestibles Frutas y verduras Higiene del hogar Higiene personal

9) Volver al Men Principal Opcin >> La primera opcin de este men nos desplegar un listado con todos los elementos de la lista y las dems solo aquellos que se correspondan con la categora seleccionada. En todos los casos la salida ser as: Lista de elementos seleccionados (TODOS): Azucar Harina Manzana Banana Fideos ID: ID: ID: ID: ID: 1 2 3 4 5

Presione ENTER para volver al Men Principal... Lista de elementos seleccionados (FRUTAS y VERDURAS): Manzana Banana ID: 3 ID: 4

Presione ENTER para volver al Men Principal... La opcin 9 simplemente nos regresa al men anterior. No deberan tener problemas con eso. Para esto deben utilizar un procedimiento como el siguiente: Procedure MostrarListaProductos(listaProductos: Productos; opcion: char); donde opcion le indicar al procedimiento el criterio por el que tiene que mostrar los productos.

Vladimir Rodrguez

112

Programacin estructurada en Pascal


3) Modificar Productos: Esta opcin del Men Principal nos mostrar las siguientes nueve:

Modificar Productos: 1) 2) 3) 4) 5) 6) 7) Todos Segn ID Segn Nombre Comestibles Frutas y verduras Higiene del hogar Higiene personal

9) Volver al Men Principal Opcin >> Para esto debern implementar un procedimiento con la siguiente firma: PROCEDURE ModificarProductos(VAR listaProductos: Productos; opcion: char); el cual funcionar del mismo modo que MostrarListaProductos. Una vez elegida la opcin de criterio segn el cual modificaremos los productos, el programa nos mostrar los datos del primer producto a modificar y luego debajo nos pedir que ingresemos los nuevos datos. Supongamos que seleccionamos la ocpin 1: Modificando productos (TODOS): Nombre: Azucar ID: 1 Stock: 15 Precio: 50,5 Categora: Comestibles Ingrese los nuevos datos: Nombre >> Azcar ID >> 123 Stock >> 18 Precio >> 50,5 Categoras (1) Comestibles (2) Frutas y verduras (3) Higiene del hogar (4)Higiene personal Ocpion >> 1 Luego de lo cual pasaramos a modificar el siguiente producto, adecuado al criterio elegido en las siete opciones disponibles. Una vez terminados todos los productos adecuados se nos mostrar el siguiente mensaje Ha terminado de modificar los productos (TODOS). Presione ENTER para volver al Men Principal... Para mostrar los datos de un producto en pantalla deben implementar un procedimiento como el siguiente: PROCEDURE MostrarDatosProducto(listaProductos: Productos; indice: integer); donde indice indicar el lugar en la lista donde se encuentra nuestro producto. Si se le pasa indice como valor igual a 0 entonces el procedimiento mostrar el mensaje: No existen datos para mostrar. Cualquier otro valor debe ser una posicin existente en nuestro arreglo de elementos. Asimismo, para buscar un producto y obtener su ndice utilizarn las siguientes funciones segn el criterio de bsqueda (ID, Nombre o Categoras): FUNCTION BuscarPorID(listaProductos: Productos; ID: integer): integer; FUNCTION BuscarPorNombre(listaProductos: Productos; nombre: string): integer; FUNCTION BuscarPorCategoria(listaProductos: Productos; categoria: categorias): integer;

Vladimir Rodrguez

113

Programacin estructurada en Pascal


donde cualquiera de estas funciones retornar como valor entero el ndice del primer elemento de la lista que cumpla con la condicin de bsqueda. Por ejemplo, si buscamos segn la categora Comestibles, se nos retornar la posicin del primer comestible en la lista listaProductos ignorando a todos los dems. De este modo debern ingenirselas para ir obteniendo todos los productos necesarios por medio de esta funcin. Estas funciones deben declararse antes que el procedimiento MostrarDatosProducto, de lo contrario no podrn llamarlas dentro del mismo. Otra opcin sera declararlas de forma interna al procedimiento, pero esto limitara su uso solo a dicho procedimiento. Para cualquiera de estas tres funciones, si no encuentran el producto buscado entonces retornaran el valor 0. Cuando se quiere modificar un producto segn su ID, como dicho producto ser nico, se pedir al usuario que ingrese un ID para buscar el producto, luego se mostrarn sus datos para modificarlo posteriormente: Modificando productos (ID): Ingrese el ID del producto a modificar: 1 Nombre: Azucar ID: 1 Stock: 15 Precio: 50,5 Categora: Comestibles Ingrese los nuevos datos: Nombre >> Azcar ID >> 123 Stock >> 18 Precio >> 50,5 Categoras (1) Comestibles (2) Frutas y verduras (3) Higiene del hogar (4)Higiene personal Ocpion >> 1 Ha terminado de modificar el producto con ID original 1. Presione ENTER para regresar al Men Principal... Para modificar productos segn su Nombre se aplicar la misma lgica que para modificarlos segn su categora. Tanto nombre como categora no son datos nicos, solo el ID es nico para cada elemento, todos los dems datos se pueden repetir. De este modo deben ir buscando a lo largo de toda la lista de productos e ir modificando aquellos que resulten adecuados al criterio de modificacin. Para todos los casos asumimos que se ingresan datos correctos. Veamos algn ejemplo ms: Modificando productos (NOMBRE): Ingrese el nombre de los productos a modificar: Azucar Nombre: Azucar ID: 1 Stock: 15 Precio: 50,5 Categora: Comestibles Ingrese los nuevos datos: Nombre >> Azcar ID >> 123 Stock >> 18 Precio >> 50,5 Categoras (1) Comestibles (2) Frutas y verduras (3) Higiene del hogar (4)Higiene personal Ocpion >> 1

Vladimir Rodrguez

114

Programacin estructurada en Pascal


No existen ms elementos con el nombre Azucar. Ha terminado de modificar los elementos con el nombre original Azucar. Presione ENTER para volver al Men Principal... Modificando productos (COMESTIBLES): Nombre: Azucar ID: 1 Stock: 15 Precio: 50,5 Categora: Comestibles Ingrese los nuevos datos: Nombre >> Azcar ID >> 123 Stock >> 18 Precio >> 50,5 Categoras (1) Comestibles (2) Frutas y verduras (3) Higiene del hogar (4)Higiene personal Ocpion >> 1 Nombre >> Harina ID >> 2 Stock >> 10 Precio >> 42,5 Categora: Comestibles Ingrese los nuevos datos: Nombre >> Harina de miz ID >> 17 Stock >> 16 Precio >> 40,5 Categoras (1) Comestibles (2) Frutas y verduras (3) Higiene del hogar (4)Higiene personal Ocpion >> 1 No existen ms elementos con la categora Comestibles. Ha terminado de modificar los elementos con la categora original Comestibles. Presione ENTER para volver al Men Principal... La opcin 9 simplemente nos mostrar el mensaje Presione ENTER para volver al Men Principal...

4) Vender: Esta opcin nos pedir el ID del producto que deseamos vender, nos mostrar sus datos luego, para pedirnos el Stock que deseamos vender, modificando esa cantidad en los datos del producto. Veremos el equivalente en dinero a la venta realizada para luego ver el mensaje de regreso al men principal. Veamos un ejemplo: Ingrese el ID del producto que desea vender: 1 Datos del producto: Nombre: Azucar

Vladimir Rodrguez

115

Programacin estructurada en Pascal


ID: 1 Stock: 15 Precio: 50,5 Categora: Comestibles Ingrese la cantidad que desea vender: 10 Dinero obtenido: 505,00 Presione ENTER para volver al Men Principal... 5) Buscar: Aqu se nos desplegarn las siguientes opciones:

Buscar productos: 1) Segn ID 2) Segn Nombre 9) Volver al Men Principal Opcin >> La primera opcin nos pedir el ID del producto que deseamos buscar y luego nos mostrar sus datos en pantalla. La segunda opcin har lo mismo pero mediante el nombre. Si el nombre se repite en ms de un producto se nos desplegarn los datos de todos ellos en el orden en el que fueron ingresados o modificados. Veamos ejemplos: Buscando segn ID: Ingrese el ID del producto que desea buscar: 2 Nombre : Harina ID: 2 Stock: 10 Precio: 42,5 Categora: Comestibles Presione ENTER para volver al Men Principal... Buscando segn NOMBRE: Ingrese el nombre del/los producto/s: Manzana Nombre: Manzana ID: 3 Stock: 10 Precio: 30,00 Categora: Frutas y Verduras Fin de la lista. Presione ENTER para volver al Men Principal... Buscando segn NOMBRE: Ingrese el nombre del/los producto/s: Banana Nombre: Banana ID: 4 Stock: 10 Precio: 37,50 Categora: Frutas y Verduras Nombre: Banana ID: 24 Stock: 8 Precio: 42,5

Vladimir Rodrguez

116

Programacin estructurada en Pascal


Categora: Comestibles Fin de la lista. Presione ENTER para volver al Men Principal... Si no hay elementos que mostrar simplemente veremos el mensaje Fin de la lista para luego ver el clsico Presione ENTER para volver al Men Principal... 6) Salir: Esta opcin simplemente terminar con la ejecucin del programa, siendo la nica forma de hacerlo. Para esto usarn la funcin exit de pascal. Limpiar la pantalla: Para este ejercicio puede resultar muy conveniente el hecho de borrar el contenido de la pantalla para mostrar uno nuevo y no que lo anterior se desplace hacia arriba. Por ejemplo, para mostrar los distintos mens, quedara mucho ms prolijo que se borre todo lo que hay en pantalla para mostrar el nuevo men en limpio, y no que este aparezca debajo de un montn de datos anteriores. Para lograr esto utilizaremos una librera de pascal. Esto no se corresponde con el cometido de este manual por lo que solo explicar cmo limpiar la pantalla. El uso de libreras lo veremos ms adelante, en un segundo manual donde abordaremos la programacin orientada a objetos, si no manejan bien todos los conceptos que hay aqu pues simplemente no tiene sentido seguir con cosas ms complejas. Qu es una librera? Bsicamente es una unidad de programa que consta de funciones y procedimientos que alguien program y puso a nuestra disposicin para que podamos utilizarlas. Esto no lo entendern muy bien ahora y no tiene demasiado sentido que me extienda, solo qudense con la idea de que nosotros podemos especificar qu librera queremos usar para luego poder invocar a sus funciones y procedimientos. Claro est que debemos conocer qu parmetro de entrada necesita cada subprograma y qu nos devolver en caso de ser una funcin. Existe una librera incluida en Free Pascal llamada CRT. Esta librera nos provee de funciones para el control de la pantalla y el teclado. De todas ellas solo nos interesa una, ClrScr, lo cual es una abreviacin de Clear Screen, que significa Limpiar Pantalla. Para indicar las libreras que vamos a usar debemos escribir la palabra reservada USES luego de la declaracin del identificador de nuestro programa. Luego de USES escribimos los nombres de nuestras libreras y ya, podemos comos llamar a sus funciones y procedimientos sin problema. Veamos un simple ejemplo de la limpieza de la pantalla: 1 PROGRAM LimpiaPantalla; 2 3 USES crt; 4 5 VAR 6 i, j: integer; 7 8 BEGIN 9 For i:=1 to 20 do 10 begin 11 For j:=1 to 20 do 12 write('#'); 13 writeln; 14 end; 15 writeln; 16 write('Presione ENTER para limpiar la pantalla...'); 17 readln; 18 clrscr; 19 write('Ha borrado la pantalla. Presione ENTER para cerrar...'); 20 readln; 21 END. Este programa lo nico que hace es dibujar un cuadro de 20x20 utilizando el carcter #, luego borra el dibujo y muestra un nuevo mensaje. La funcin clrscr puede ser llamada cada vez que queramos. Hasta aqu va esta parte del programa. En s no cambiaremos mucho su funcionamiento, sino que utilizaremos nuevas herramientas para optimizarlo, pero esto lo veremos a continuacin. Si necesitan que corrija sus programas, sus cdigos fuente, si tienen dudas, si quieren mis propios cdigos fuente del programa completo o de alguno de los procedimientos o funciones que les propongo implementar, si necesitan un ejecutable de ejemplo para ver todo esto en funcionamiento simplemente escrbanme a mstrvladi@hotmail.com solicitndome lo que les haga falta y les responder a la brevedad. Mucha suerte. Intenten hacer este programa antes de continuar, ya que me basar en esto para aplicar muchos de los conceptos que an nos faltan por ver.

Vladimir Rodrguez

117

Programacin estructurada en Pascal


La funcin WITH... DO: Esta funcin es solo para aplicarse con registros y su utilidad radica casi nicamente en hacernos escribir mucho menos ya que nos facilita el acceso a las variables de un registro. Veamos un simple ejemplo de su funcionamiento. Primero escribir un simple programa que dado un registro asignar valores a sus variables: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 PROGRAM PrimeroSinWith; TYPE Grados= (primero, segundo, tercero, cuarto, quinto, sexto); Estudiante= RECORD Nombre: String; Edad, Documento: Integer; Grado: Grados; END; VAR Alumno: Estudiante; BEGIN Alumno.Nombre:= 'Vladimir'; Alumno.Edad:= 18; Alumno.Documento:= 12345 Alumno.Grado:= sexto; END. Ahora veamos el mismo programa pero utilizando WITH... DO: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 22 23 PROGRAM AhoraConWith; TYPE Grados= (primero, segundo, tercero, cuarto, quinto, sexto); Estudiante= RECORD Nombre: String; Edad, Documento: Integer; Grado: Grados; END; VAR Alumno: Estudiante; BEGIN With Alumno do begin Nombre:= 'Vladimir'; Edad:= 18; Documento:= 12345 Grado:= sexto; end; END.

Como ven, su nico cometido es evitarnos tener que escribir constantemente el nombre de nuestra variable del tipo registro seguido de un punto para luego especificar la variable del registro a la que queremos acceder. Utilizando WITH... DO simplemente escribimos el nombre de nuestra variable del tipo registro una nica vez y luego nos dirigimos a las variables internas directamente. Claro est que esto funciona solo dentro de los lmites del BEGIN y el END correspondientes a la funcin WITH, o sea, en nuestro programa accedemos directamente a las variables de Alumno solo dentro de las lneas 16 y 22 que corresponden al bloque de WITH. Del mismo que en estos ejemplos utilizamos los campos del registro para asignarles valores, podemos utilizarlos dentro de un WITH para hacer cualquier cosa de las que ya conocemos.

Vladimir Rodrguez

118

Programacin estructurada en Pascal


Ambigedad con WITH... DO: Esto solo ser un simple ejemplo para que conozcan el tipo de confusiones que se puede tener si no se usa la funcin WITH con cuidado: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 PROGRAM EjemploAmbiguo; TYPE Grados= (primero, segundo, tercero, cuarto, quinto, sexto); Estudiante= RECORD Nombre: String; Edad, Documento: Integer; Grado: Grados; END; VAR Alumno: Estudiante; Grado: integer; //Prestar atencin a esta variable. BEGIN With Alumno do begin Nombre:= 'Vladimir'; Edad:= 18; Documento:= 12345 Grado:= 10; //Error, Grado aqu representa a Alumno.Grado Grado:= sexto; //Esto s es correcto. end; END.

Como ven, solo conviene utilizar WITH cuando necesitamos trabajar nicamente con todos los datos del registro sin involucrar otros. Claro est que si no los identificadores no se repiten no hay problema. Lo que sucede en este programa es que el registro tiene un campo llamado Grado y a su vez he declarado una variable global llamada Grado. Esto es totalmente posible ya que en realidad no estoy repitiendo identificadores, la variable del registro en realidad se llama Alumno.Grado y mi variable global solo Grado. Sin embargo, dentro de WITH tendremos el problema que se ve en el ejemplo de la lnea 21, ya que intentamos asignar el valor 10 a nuestra variable global, pero para el compilador all nos estamos refiriendo a la variable Alumno.Grado que es de tipo Grados y no puede asumir valores enteros.

Vladimir Rodrguez

119

Programacin estructurada en Pascal Registro con variante


Esto no es en s un nuevo tema, sino una aplicacin prctica para lo que ya conocemos. Un registro con variante suele utilizarse para representar una entidad que puede pertenecer a diferentes categoras que tienen diferentes datos pero que a su vez existen datos comunes a todas las categoras. Como para m no existe mejor explicacin que un ejemplo, vamos a ello: Supongamos que dada una persona de nuestra empresa puede ser Encargado o Pen, si es encargado entonces le asignamos un grado que puede ser Bajo, Medio o Alto, y si es pen le asignamos un rango que puede ser Novato o Prctico. Asimismo un pen puede tener una carga horaria de entre 40 y 48 horas semanales; para un encargado no se especifica. Para cualquier caso guardamos adems el nombre y el documento del funcionario. Como pueden ver los datos variarn segn el tipo de funcionario (categora) pero a su vez tenemos datos comunes a todos, que son el documento y el nombre. Veamos la estructura del registro: TYPE Categorias= (encargado, peon); Funcionario= Record Nombre: String; Documento: Integer; Case categoria: Categorias of encargado: (grado: (Bajo, Medio, Alto)); peon: (rango:(Novato, Practico); cargaHoraria: 40..48); End; Explicar un poco esto: El registro Funcionario funciona igual que todos los dems vistos hasta ahora. Tenemos la variable Nombre del tipo String, la variable Documento del tipo Integer y luego la variable categoria del tipo Categorias. Como pueden ver esta variable se declara y se define en el encabezado de un CASE... OF, cosa que hasta ahora no habamos visto y solo utilizaremos esta forma de declarar un CASE para los registros con variante. Dependiendo del valor que tome esta variable definiremos las siguientes:

Si categoria toma el valor encargado entonces definimos la variable grado como un enumerado que corresponde a los grados de un encargado; si toma el valor peon entonces nos definimos la variable rango como otro enumerado con los rangos de un pen y su vez definimos la variable cargaHoraria como un subrango de enteros que va de 40 a 48 inclusive. Como en este caso definimos dos variables diferentes las separamos por punto y coma. Todas las variables declaradas para cada caso van entre parntesis. Las variables de un mismo tipo pueden declararse todas juntas separndolas por coma. Esto funciona como en los encabezados de un procedimiento o una funcin. A pesar de darle esta forma, el registro funciona como si estuviera declarado de esta manera:
Funcionario= Record Nombre: String; Documento: Integer; categoria: Categorias; grado: (Bajo, Medio, Alto); rango:(Novato, Practico); cargaHoraria: 40..48); End; Sin embargo, darle una aplicacin correcta a la estructura anterior hace que un cdigo sea mucho ms legible, corto, entendible y no van a creer cuantos errores de programacin nos ahorramos. Adems, la estructura del registro con variante nos da una visin mucho ms clara de la informacin que estamos manejando y de cmo utilizarla. El acceso a las variables (campos) del registro sigue siendo como siempre a pesar de que su declaracin ha cambiado, por eso mismo les he aclarado que el registro con variante funciona como si fuera este ltimo que ven aqu, sin embargo en este ltimo no es posible visualizar qu tipo de informacin corresponde a los distintos casos me comprenden? En el primero se ve claramente que si el funcionario es encargado debemos asignarle un grado, y si es pen le asignamos un rango y una carga horaria. Declarando el registro como uno normal da la impresin de que todos esos datos irn para todos los funcionarios, o sea, todos tienen una categora, un grado, un rango y una carga horaria, pero en realidad no es as. Veamos entonces un simple programa en el que tenemos un arreglo de tres celdas el cual contendr los datos de los empelados en cada una de ellas, o sea, tenemos tres personas. Los datos sern ledos de la entrada estndar y asumiremos que son correctos siempre. Utilizar la estructura del FOR para esto ya que ingresaremos tres funcionarios s o s, no me interesa nada ms:

Vladimir Rodrguez

120

Programacin estructurada en Pascal


1. PROGRAM RegistroVariante; 2. 3. CONST 4. N= 3; 5. 6. TYPE 7. Categorias= (encargado, peon); 8. 9. Funcionario= Record 10. Nombre: String; 11. Documento: Integer; 12. Case categoria: Categorias of 13. encargado: (grado: (Bajo, Medio, Alto)); 14. peon: (rango:(Novato, Practico); cargaHoraria: 40..48); 15. End; 16. 17. Personal= Array[1..N] of Funcionario; 18. 19. VAR 20. MisFuncionarios: Personal; 21. i: integer; 22. opcion: char; 23. 24. BEGIN 25. For i:=1 to N do 26. begin 27. writeln('Funcionario nmero ',i,':'); 28. writeln; 29. write('Nombre: '); 30. readln(MisFuncionarios[i].Nombre); 31. write('Documento: '); 32. readln(MisFuncionarios[i].Documento); 33. writeln('Seleccione una categora: (1) Encargado'); 34. writeln(' (2) Pen'); 35. write('Opcin: '); 36. readln(opcion); 37. 38. Case opcion of 39. '1': begin 40. writeln; 41. writeln('Seleccione un grado para el encargado: (B) Bajo'); 42. writeln(' (M) Medio'); 43. writeln(' (A) Alto'); 44. write('Opcin: '); 45. readln(opcion); 46. 47. Case opcion of 48. 'b', 'B': MisFuncionarios[i].grado:= Bajo; 49. 'm', 'M': MisFuncionarios[i].grado:= Medio; 50. 'a', 'A': MisFuncionarios[i].grado:= Alto; 51. End; 52. end; 53. '2': begin 54. writeln; 55. writeln('Seleccione un rango para el pen: (N) Novato'); 56. writeln(' (P) Prctico'); 57. write('Opcin: '); 58. readln(opcion); 59. 60. Case opcion of 61. 'n', 'N': MisFuncionarios[i].rango:= Novato; 62. 'p', 'P': MisFuncionarios[i].rango:= Practico; 63. End;

Vladimir Rodrguez

121

Programacin estructurada en Pascal


64. 65. 66.

writeln; write('Ingrese la carga horaria semanal del pen (40 a

48 hs): '); 67. readln(MisFuncionarios[i].cargaHoraria); 68. end; 69. End; 70. 71. writeln; 72. end; 73. END. Explicar un poco este programa, aunque no debera darles problemas ya que en s no es nada complejo, solo leemos y asignamos datos, nada ms. En la lnea 17 declaramos el tipo Personal que no es ms que un arreglo del tipo Funcionario, o sea, un arreglo donde cada celda representa a un registro. En la lnea 20 declaro una variable del tipo Personal, o sea, creo mi arreglo para trabajar; luego declaro la tpica variable i del tipo integer para iterar en las celdas del arreglo. Finalmente declaramos la variable opcion del tipo char, esta la usaremos para asignar valores a los tipos enumerados ya que estos no pueden leerse de la entrada estndar. El bloque principal de nuestro programa es un enorme FOR que iterar desde 1 a N en nuestro arreglo, o sea en todas sus celdas. Como N vale 3, nuestro FOR iterar 3 veces con lo cual terminar nuestro programa. En la lnea 30 leemos directamente el campo Nombre de la celda i de nuestro arreglo; hacemos lo mismo en la lnea 32 para el campo Documento. Luego desplegamos en pantalla las opciones para la categora de nuestro funcionario i, las cuales las leeremos como caracteres en la variable opcion. Dependiendo e la opcin elegida por el usuario ser la informacin que pediremos. Si se ingresa un 1 entonces pediremos los datos para un encargado y se ingresa un 2 pediremos los datos para un pen. Esto lo ven con el CASE opcion OF que inicia en la lnea 38 y cierra en la lnea 69. El funcionamiento de esta estructura no debera darles problemas. Lo que cabe destacar aqu es que, por ejemplo, si la opcin elegida es la 1, o sea, si estamos ingresando los datos de un encargado, solo usaremos las variables que guardan la informacin pertinente a esa categora y no tocamos las dems porque no nos interesan. Lo que quiero decir es que, por ejemplo, para un encargado no tocamos en ningn momento las variables rango o cargaHoraria porque no nos interesan y no trabajaremos con ellas en un posterior tratamiento de la informacin. Es un error asignar valores a campos que no se corresponden con la informacin que estamos tratando, o sea, si vamos a trabajar con un pen entonces nos aseguramos de ello y luego asignamos los valores solo y nicamente a las variables que son pertinentes a la categora de pen. Podramos, si queremos, asignar un valor de grado a pesar de estar trabajando con la categora pen, el compilador lo permitir tranquilamente y no habr ningn tipo de error en el programa en s, pero est mal porque un pen no tiene grado sino rango y no nos importa los valores que grado pueda tomar en este caso.

Vladimir Rodrguez

122

Programacin estructurada en Pascal Arreglo con tope:


Esta no es una nueva estructura sino una nueva implementacin de una estructura conocida, los arreglos. A estas alturas deberan ser capaces de trabajar perfectamente con ellos. Como bien saben, los arreglos se definen de un tamao fijo y este no puede variar a lo largo del programa ya que es asignado en tiempo de compilacin. Ahora bien, imaginen que necesitamos almacenar datos pero que a priori no sabemos cuantos, por ejemplo, imaginen que en el programa del supermercado no sabemos cuantos productos tendremos que ingresar, puede ser uno o pueden ser treinta cmo hacemos? En principio utilizaremos los arreglos, luego veremos cmo se hace esto realmente utilizando memoria dinmica, nuestro ltimo tema. Bien, vamos a los arreglos con tope, la idea es la siguiente: Me asigno un nmero mximo de objetos a almacenar, lo cual definir la dimensin del arreglo; luego voy registrando cuntos elementos almaceno en el mismo y ser hasta ese punto donde navegar en el arreglo, no me interesar el resto. Por ejemplo, si nos definimos un arreglo de 50 celdas del tipo carcter, el cual usaremos para guardar palabras que pueden tener entre una y cincuenta letras, al guardar una palabra de diez letras solo nos interesa recorrer las primeras diez celdas del arreglo, las otras cuarenta no sern necesarias. En este caso mi tope ser el nmero 10 y lo implementar como si se tratase del final de mi arreglo. Veamos un ejemplo de esto en un cdigo de un simple programa que espera recibir de la entrada un cdigo numrico de tamao variable con un mximo de 20 caracteres. La idea es verificar que efectivamente el cdigo sea numrico. No podemos leer la entrada estndar como un entero porque si el usuario pone otra cosa que no sean nmeros el programa dar un error en tiempo de ejecucin, nada recomendable. Lo mismo sucede con el tipo real. Si leemos la entrada como string no tendremos problemas en ejecucin, sin embargo cmo verificamos que la cadena ingresada sea justamente numrica? 1. PROGRAM ArrayConTope; 2. 3. CONST 4. MaxCaracteres= 20; 5. 6. TYPE 7. Codigo= Array[1..MaxCaracteres] of char; 8. 9. VAR 10. MiCodigo: Codigo; 11. Tope, i: integer; 12. error: boolean; 13. 14. 15. BEGIN 16. Tope:= 0; //Representa un cdigo (palabra) nulo ya que no existe celda de ndice 0. 17. write('Ingrese un cdigo numrico: '); //Mensaje para el usuario. 18. 19. //Leemos hasta el fin de lnea o hasta llegar al mximo permitido. 20. //Notar que leemos directamente sobre la celda del arreglo. 21. Repeat 22. Tope:= Tope + 1; 23. read(MiCodigo[Tope]); 24. Until (eoln) or (Tope=MaxCaracteres); 25. 26. readln; //Consumimos el fin de lnea. 27. 28. //Iteramos por nuestro arreglo hasta que exista un caracter no numrico 29. //o hasta llegar al tope sin haber encontrado error. 30. i:=0; 31. Repeat 32. i:= i + 1; 33. error:= (ord(MiCodigo[i])<ord('0')) or (ord(MiCodigo[i])>ord('9')); 34. Until (error) or (i=Tope); 35. 36. If error then 37. writeln('Error en cdigo, no es numrico.') 38. else 39. writeln('Cdigo correcto.'); 40. END.

Vladimir Rodrguez

123

Programacin estructurada en Pascal


Podramos decir que el programa anterior no est mal ya que aplica la estructura del arreglo con tope correctamente, sin embargo no es la implementacin ms adecuada (esto depender del punto de vista de los programadores). Dado que el arreglo con tope en realidad est representando un conjunto, el cual puede ser vaco cuando el tope vale 0 o puede contener elementos variables a lo largo del programa, la implementacin correcta es aquella que lo visualiza como una nica entidad. De este modo, la forma correcta de aplicar el programa anterior es la siguiente: 1. PROGRAM ArrayConTope; 2. 3. CONST 4. MaxCaracteres= 20; 5. 6. TYPE 7. ConjuntoCodigo= Record 8. Codigo: Array[1..MaxCaracteres] of char; 9. Tope: 0..MaxCaracteres; 10. End; 11. 12. VAR 13. MiCodigo: ConjuntoCodigo; 14. i: integer; 15. error: boolean; 16. 17. 18. BEGIN 19. MiCodigo.Tope:= 0; //Representa un cdigo (palabra) nulo ya que no existe celda de ndice 0. 20. write('Ingrese un cdigo numrico: '); //Mensaje para el usuario. 21. 22. //Leemos hasta el fin de lnea o hasta llegar al mximo permitido. 23. //Notar que leemos directamente sobre la celda del arreglo. 24. Repeat 25. MiCodigo.Tope:= MiCodigo.Tope + 1; 26. read(MiCodigo.Codigo[MiCodigo.Tope]); 27. Until (eoln) or (MiCodigo.Tope=MaxCaracteres); 28. 29. readln; //Consumimos el fin de lnea. 30. 31. //Iteramos por nuestro arreglo hasta que exista un caracter no numrico 32. //o hasta llegar al tope sin haber encontrado error. 33. i:=0; 34. Repeat 35. i:= i + 1; 36. error:= (ord(MiCodigo.Codigo[i])<ord('0')) or (ord(MiCodigo.Codigo[i])>ord('9')); 37. Until (error) or (i=MiCodigo.Tope); 38. 39. If error then 40. writeln('Error en cdigo, no es numrico.') 41. else 42. writeln('Cdigo correcto.'); 43. END. Ejercicio 0: Modifiquen este programa para utilizarlo con WITH...DO. A continuacin les expongo varios ejercicios, todos diseados por docentes de Facultad de Ingeniera. Todos los ejercicios pueden y deben ser resueltos con lo visto hasta el momento. La informacin que yo les he dado en este manual resulta incluso mucho ms completa que la que dan los profesores en las clases ya que ellos apuntan a que los estudiantes investiguen lo que no conocen y se las arreglen solos en muchos casos, usando clases de consulta como apoyo a las dudas. Ustedes pueden escribirme a mi correo electrnico mstrvladi@hotmail.com para consultar todas las dudas. Muchos ejercicios son de gran dificultad, identificar las dificultades de cada ejercicio con colores: Verde (dificultad baja), Amarillo (Dificultad Media), Naranja (Dificultad Media Alta), Rojo (Dificultad Alta). Algunos ejercicios apuntan, adems de a la programacin en s, al uso de conocimientos matemticos que no se imparten aqu, por lo cual simplemente aclarar para esos casos que se requiere el conocimiento matemtico y ustedes decidirn si lo tienen o no para realizar el ejercicio. Fuera de todos aquellos que requieren matemtica, usedes deben ser capaces de resolver todos estos ejercicios. Recuerden que la mejor herramienta para la programacin es la prctica. Si no se ponen con estas cosas no llegarn a nada, y tratar de avanzar para ver que viene pero dejando cosas en el camino no servir de nada. Adelante!!!

Vladimir Rodrguez

124

Programacin estructurada en Pascal


Ejercicio 1: Examinen la siguiente declaracin : CONST CANT_PERS = 100; MAX_CADENA = 30; TYPE Cadena = RECORD letras : ARRAY[1..MAX_CADENA] OF CHAR; largo : 0..MAX_CADENA; END; Persona = RECORD nombre : Cadena; edad : 0..120; estado : (casado, soltero, divorciado); salario : REAL; exenciones : 0..MAXINT; END; VAR juanita : Persona; grupo : ARRAY[1..CANT_PERS] OF Persona; Determinen cules de las siguientes proposiciones son vlidas:

a)
grupo [1] := juanita;

b) c)

grupo [1].nombre := 'juanita';

Read (grupo [1].estado);

d) e)

WITH grupo DO writeln (nombre);

WITH grupo [100] DO BEGIN Read (edad); END;

f)

WITH juanita DO BEGIN nombre := grupo [50].nombre; salario := grupo [1].salario END;

Ejercicio 2: Supongan que una sociedad genealgica tiene un arreglo de registros que indican la fecha de nacimiento y subndice en el arreglo de los registros de los padres y madres de varias personas. El arreglo de registros y las variables correspondientes podran ser parecidos a stos :

Vladimir Rodrguez

125

Programacin estructurada en Pascal


CONST MAXPERSONAS = 1000; MAXCAD = 20; TYPE Cadena = RECORD letras : Array[1..MAXCAD] Of Char; largo : 0..MAXCAD; END; UnaPersona = RECORD nombre : Cadena; FechNac : RECORD (* Fecha de nacimiento *) mes : 1..12; dia : 1..31; anio : 0..MAXINT END; IndMadre, IndPadre : 0..MAXPERSONAS; END; Familia = RECORD pers : ARRAY[1..MAXPERSONAS] OF UnaPersona; tope : 0..MAXPERSONAS; END; VAR historia : Familia; usted : Cadena; Los campos IndMadre e IndPadre contienen el subndice en el arreglo historia de los registros de la madre y el padre. Este valor ser cero si no se dispone de la informacin correspondiente. Supongan que la variable usted contiene el nombre de una persona; exhiban entonces los nombres y fechas de nacimiento de los padres y los cuatro abuelos de esa persona (si es que se contienen la informacin).

Ejercicio 3: Escriba una funcin en PASCAL llamada alfa que tenga como parmetro una cadena de caracteres (representada con un arreglo con tope) llamada frase y una variable de tipo carcter llamada letra. La funcin alfa produce el nmero de apariciones del carcter letra en la frase.

Ejercicio 4: (Requiere conocimientos de matemtica bsica de nivel secundario, concretamente deben saber hallar las races de cualquier polinomio de segundo grado (funcin cuadrtica)) Implementen un procedimiento que calcule las races de una ecuacin de segundo grado. El cabezal del procedimiento debe de ser el siguiente: Procedure Raices(a, b, c : Real; Var r : TipoRaices); 1. Definan el tipo TipoRaices utilizando la estructura de registro con variante. 2. Implementen el procedimiento pedido.

Ejercicio 5: (Este conocimiento est basado en una notacin matemtica comn para cualquier estudiante pero avanzada para su tratamiento. El conocimiento necesario se corresponde con los ltimos aos de secundaria y/o inicios de estudios terciarios) Se considera el tipo de dato Nerr que es la unin de los nmeros naturales (N) con el conjunto Err. El conjunto Err se define como {diverr, reserr, argerr}, donde diverr es el error de la divisin por cero,reserr es el error de la resta con resultado negativo y argerr es el error de cualquier operacin donde alguno de sus argumentos no es natural. Se definen las siguientes operaciones sobre elementos del tipo Nerr:

Vladimir Rodrguez

126

Programacin estructurada en Pascal


division: Nerr x Nerr Nerr Si a pertenece a N y b pertenece a N - {0} ==> divivision(a,b) = a DIV b; Si a pertenece a N y b = 0 ==> division(a,b) = diverr; Si a pertenece a Err o b pertenece a Err ==> division(a,b) = argerr; resta: Nerr x Nerr Nerr Si a pertenece a N y b pertenece a N y a >= b ==> resta(a,b) = a - b; Si a pertenece a N y b pertenece a N y a < b ==> resta(a,b) = reserr; Si a pertenece a Err o b pertenece a Err ==> resta(a,b) = argerr; suma: Nerr x Nerr Nerr Si a pertenece a N y b pertenece a N ==> suma(a,b) = a + b; Si a pertenece a Err o b pertenece a Err ==> suma(a,b) = argerr; producto: Nerr x Nerr Nerr Si a pertenece a N y b pertenece a N ==> producto(a,b) = a * b; Si a pertenece a Err o b pertenece a Err ==> producto(a,b) = argerr; 1. Definan en PASCAL el tipo Err. 2. Definan en PASCAL el tipo Nerr. 3. Implementen los procedimientos que implementan respectivamente las operaciones divisin, resta, suma y producto del tipo Nerr. PROCEDURE PROCEDURE PROCEDURE PROCEDURE division (n1:Nerr; n2:Nerr; VAR n3:Nerr); resta (n1:Nerr; n2:Nerr; VAR n3:Nerr); suma (n1:Nerr; n2:Nerr; VAR n3:Nerr); producto (n1:Nerr; n2:Nerr; VAR n3:Nerr);

Ejercicio 6: (Matemtica de nivel terciario (lgebra lineal de matrices) Se desea implementar en PASCAL el producto de matrices de elementos de tipo Nerr. Las matrices a operar podrn tener diferentes dimensiones. Se sabe que si una matriz tiene dimensin mxn, m y n son enteros positivos que nunca superarn a constantes X e Y respectivamente. El producto entre matrices de tipo Nerr se define de manera anloga al producto de matrices de nmeros naturales con la suma y el producto para el tipo Nerr dado en el ejercicio anterior. Sea la matriz m1 de dimensin m x n y la matriz m2 de dimensin p x q. Si n = p el producto m1 x m2 tendr dimensin m x q, en caso contrario diremos que el producto falla. Definir en PASCAL el tipo MNerr, que representa las matrices de dimensiones m x n de tipo Nerr, para cualquier m entre 1 e Y, y para cualquier n entre 1 y X. Puede asumir que X e Y son mayores o iguales que 1. Adems MNerr debe tener un valor de error merr para el caso en que el producto de matrices falle. Implementar el procedimiento: PROCEDURE mprod (m1:MNErr; m2:MNerr; VAR m3:MNerr); El procedimiento mprod recibe dos matrices m1 y m2, retornando en m3 el producto m1 x m2 o merren caso de que dicho producto falle.

Ejercicio 7: En una isla del Caribe una banda de piratas se gana la vida asaltando barcos mercantes. Anualmente en la isla se realiza un evento multitudinario llamado la entrega de los premios Calavera. Para este ao los piratas estn pensando en entregar el premio Calavera de Oro al pirata que haya conseguido mas dinero asaltando barcos para la banda. Como usualmente los piratas discuten a quin le corresponden los premios en trifulcas interminables y sangrientas, este ao la comisin directiva de la banda ha decidido informatizar el registro de logros de los piratas en los distintos asaltos, con la esperanza de terminar as con algunas de las discuciones sobre los crditos que le corresponden a cada pirata.

Los logros de los piratas durante el ao se organizan en la siguiente estructura:

Vladimir Rodrguez

127

Programacin estructurada en Pascal


CONST MAXPIRATAS=10000; MAXASALTOS=500; un pirata. *) MAXDIGITOSCI=8;

(* Limite de piratas que pueden vivir en la isla. *) (* Limite de asaltos a los que estadisticamente puede sobrevivir (* Cantidad de digitos para almacenar un numero de cdula. *)

TYPE TipoCI=ARRAY[1..MAXDIGITOSCI] OF CHAR; TipoFecha=RECORD dia:1..31; mes:1..12; anho:INTEGER END; TipoAsalto=RECORD nombre_barco:ARRAY[1..30] OF CHAR; fecha:TipoFecha; botin:INTEGER banda *) END;

(* Nombre del barco asaltado *) (* Fecha del atraco *) (* Suma de dinero obtenida para la

ConjuntoAsaltos=RECORD (* Contiene informacin sobre los asaltos asaltos:ARRAY[1..MAXASALTOS] OF TipoAsalto; tope:0..MAXASALTOS END; TipoPirata=RECORD nombre:ARRAY[1..30] OF CHAR; CI:TipoCI; CASE estavivo:BOOLEAN OF pirata *) TRUE: (asaltos:ConjuntoAsaltos); asaltos *) *) FALSE: () END; Banda=RECORD pirata:ARRAY[1..MAXPIRATAS] OF TipoPirata; piratas de la banda *) tope:0..MAXPIRATAS *) END;

*)

(* Nombre del pirata *) (* Cdula de identidad *) (* Indica el estado vital actual del (* Contiene informacin sobre los (* realizados por el pirata

(* Contiene informacin de los (* Indica cantidad de piratas

Se pide:

Parte a)
Implementar la funcin: FUNCTION dinero_obtenido_por_pirata(pirata:TipoCI, anho:INTEGER, b:Banda) : INTEGER; la cual debe recibir la CI de un pirata, un ao y una banda, y retornar la suma de dinero obtenida por el pirata para la banda en ese ao. En caso de que el pirata se encuentre muerto o no se encuentre en la banda debe retornar 0. Se sugiere implementar primero funciones:

Vladimir Rodrguez

128

Programacin estructurada en Pascal


FUNCTION CIiguales (ci1, ci2:TipoCI):BOOLEAN; (* Retorna TRUE si "ci1" y "ci2" son iguales, FALSE si no. *) FUNCTION contar_dinero (ca:ConjuntoAsaltos; anho:INTEGER):INTEGER; (* Retorna la suma del dinero obtenido en los asaltos del conjunto "ca" realizados durante el ao "anho". *)

Parte b)
Implementar la funcin: PROCEDURE hallar_ganadores(piratas:Banda, anho:INTEGER; VAR piratas_merecedores:ConjuntoCIs) la cual dada una banda de pirata y un ao, devuelve en piratas_merecedores las cdulas de los piratas vivos merecedores del premio Calavera de Oro. Tengamos en cuenta, que varios piratas pueden coincidir en la cantidad de dinero obtenido para la banda y que no hayan otros piratas que los superen. ConjuntoCIs se declara como sigue: TYPE ConjuntoCIs=RECORD cedulas:ARRAY[1..MAXPIRATAS] OF TipoCI; (* Arreglo de cedulas *) tope:0..MAXPIRATAS (* Cantidad de cdulas en el array *) END;

Ejercicio 8: Examen Agosto 2001 Se desea trabajar con una aritmtica de Naturales de hasta 100 dgitos. Los Enteros de PASCAL no soportan dicha aritmtica, por lo que se piensa utilizar la siguiente representacin de Naturales basada en arreglos con tope: CONST MaxDig = 100; TYPE Digito = 0..9; Natural = RECORD digitos : ARRAY[1..MaxDig] OF Digito; tope : 0..MaxDig; END; Implementar la suma de Naturales representados en trminos de la estructura anterior. Utilizar el siguiente cabezal: Procedure Suma(a, b : Natural: Var c : Natural);

Vladimir Rodrguez

129

Programacin estructurada en Pascal


BASE PRODUCTOS Parte 2 Aadiremos dos funcionalidades ms a nuestro programa: Captura de Errores y una Lista Variable de Elementos a almacenar. Para esto tendrn que modificar bastante su cdigo, lo cual puede ser bastante complicado y les mostrar la realidad de trabajar con un cdigo ya hecho. Si no utilizaron buenos comentarios estarn en problemas ya que tendrn que rememorar lo que hace su programa e incluso con ellos tendrn que acomodar su cabeza nuevamente a una lgica puntual. Cada programa es un mundo, tiene sus problemas y complicaciones, su estructura; y para cada uno deben adecuar su mente. Imaginen lo que es trabajar con el cdigo de otra persona cuya cabeza funciona de una forma totalmente diferente a la nuestra, cuya lgica nos hace rompernos la cabeza en el intento por comprendela. Pues ese es el mundo de la programacin, de la creacin de software, y cranme, lo que yo les he mostrado en este manual no es nada. En prximas entregas iremos sumergindonos ms en un mundo donde la magia es posible, donde la imaginacin es prcticamente el nico lmite, donde el ingenio es la mejor herramienta, donde la paciencia es la mejor virtud. Sin embargo nada ser sencillo, necesitarn sentarse a pensar horas cmo lograr tal o cual cosa, analizar una y otra vez dnde cornos est el error que hace a nuestro programa tirarnos cualquier cosa en un caso concreto PERO SI EN TODOS LOS DEMS CASOS FUNCIONA!!! Muchas veces pensarn que no hay solucin, que necesitan alguna otra herramienta, sin embargo este manual ha apuntado a que ustedes puedan lograr grandes soluciones con herramientas bsicas. PASCAL tiene muchas cosas ms que nosotros ni hemos nombrado y que en ciertos aspectos solucionaran muchos problemas de forma automtica. Lenguajes superiores lograrn con dos palabras resolver lo que a ustedes les ha llevado diez o ms lneas de cdigo y horas de rompedero de cabeza, pero as se aprende y as, con esos lenguajes superiores, lograrn resolver cosas que tal vez otras personas no podran. Bien, vayamos a nuestro programa. Nuestro programa deber tiranos el mensaje ERROR: Dato inesperado, ingrese un dato vlido para cualquier caso en el que ingresemos algo inadecuado en cualquier entrada. Siempre que se muestre el mensaje de error el programa deber quedar a la espera de un nuevo ingreso para el mismo dato. Detallar aqu los posibles errores en las entradas y dar ejemplos de ejecuciones:

Nombre: El nombre de un producto debe estar formado nicamente por nmeros y/o letras maysculas y/o minsculas. Cualquier otro carcter se tomar como invlido. ID: El ID debe ser un nmero entero positivo, o sea, un natural. Si el dato ingresado no se corresponde con un nmero entero positivo o directamente no es un nmero lo consideraremos como error. Para el ID tambin deberemos corroborar que no se repita en todos los ingresos anteriores, ya que eso tambin sera un error. Stock: Debe ser un nmero entero positivo. Tiene las mismas restricciones que el ID con la excepcin de Stock s puede repetirse. Precio: Este dato debe ser un nmero real positivo, en caso de ser negativo o no ser un nmero lo consideraremos como error. Este dato les traer problemas de captura ya que leer la entrada como carcter y luego pasarla a real no es tan sencillo como pasarla a entero. Categora: Para este dato solo debemos corroborar que lo ingresado se corresponda con una de las opciones mostradas en pantalla, de lo contrario ser un error. Esto se aplicar a todas las pantallas de nuestro programa en las que el usuario deba elegir una de varias opciones.

Para controlar el nombre ingresado deben implementar una funcin como la siguiente: FUNCTION NombreCorrecto(nombre: CadenaChar): Boolean; donde CadenaChar ser un tipo global declarado de la siguiente manera: CONST MaxLargoNombre: 20; TYPE CadenaChar= RECORD nombre: Array[1..MaxLargoNombre] of Char; tope: 0..MaxLargoNombre; END; La funcin NombreCorrecto devolver TRUE si la cadena ingresada cumple las condiciones de ms arriba, FALSE en caso contrario.

Vladimir Rodrguez

130

Programacin estructurada en Pascal


Para corroborar que la entrada corresponde a un entero positivo deben utilizar la siguiente funcin: FUNCTION EsEnteroPositivo(numero: CadenaChar): Boolean la cual devolver TRUE si la entrada es un entero positivo o 0. Esto lo usarn para ID y para Stock, y tal vez para algn otro caso ms donde ustedes crean que sea pertinente. No admitimos el signo de + en la entrada. Del mismo modo comprobaremos si la entrada se corresponde a un real positivo : FUNCITION EsRealPositivo(numero: CadenaChar): Boolean; la cual obviamente devolver TRUE si la entrada es un real positivo o FALSE en caso contrario. Recuerden que tomamos como real positivo que contenga nmeros y/o una sola coma. No admitimos el signo de + en la entrada. De este modo, entradas correctas seran las siguientes: 1 Recordar que los nmeros enteros son reales. 10 10,0 ,12 equivale a 0,12 por lo cual es correcto. 1325,123 Entradas incorrectas seran: +1 +1,23 -1,23 -0 +0 12,12,3 ,0,1 12,-1 Para obtener el valor entero de una entrada correcta deben implementar la funcin siguiente: FUNCTION StringToInt(numero: CadenaChar): Integer; la cual devolver dicho valor. Esta funcin recibe una cadena de caracteres correcta, por lo cual la verificacin de error debe hacerse antes de su llamada. Del mismo modo implementarn una funcin para obtener el valor real de una cadena de caracteres correctos: FUNCTION RealToInt(numero: CadenaChar): Real; Esta funcin, como dije antes, les traer problemas porque no es lo mismo pasar una cadena de caracteres a un valor entero que a un valor real. Les explicar la lgica que se me ocurri a m para su implementacin: Un nmero real est constituido de dos partes, la que est antes de la coma y la que est despus, o sea, la parte entera y la parte real. Por ejemplo:

1 : Parte entera 1, parte real 0. 1,000: Parte entera 1, parte real 0. 01,0: Parte entera 1, parte real 0. 12,52: Parte entera 12, parte real 52.

El truco est entonces en obtener estas dos partes por separado como nmeros enteros, de este modo si tenemos el 12,52 tendremos por un lado el 12 y por otro lado el 52, ambas partes como enteros, lo cual es fcil llevar a valor integer con la funcin StringToInt. Una vez tenemos el entero 12 por un lado y el entero 52 por otro debemos establecer el 52 como el real 0,52 y sumrselo al 12 con lo cual obtenemos 12,52. 12 + 0,52= 12,52.

Vladimir Rodrguez

131

Programacin estructurada en Pascal


Para obtener el 0,52 a partir de 52 basta con dividirlo entre 100. De este modo, si nuestra parte real tiene un solo dgito debemos dividirla entre 10, si tiene dos dgitos debemos dividirla entre 100, si tiene tres entre 1000 y as sucesivamente. Por ejemplo: 123,146= 123 + 146/1000 1,2365= 1 + 2365/10000 01,0= 1 + 0/10

Espero que con esto puedan implementar correctamente la funcin RealToInt. Cualquier duda estoy a su disposicin en mi correo mstrvladi@hotmail.com. Para comprobar que la opcin de la categora seleccionada es correcta, o para comprobar que la opcin de un men se corresponde con una de las disponibles deben implementar una funcin como la siguiente: FUNCTION OpcionCorrecta(inicioRango, finRango: char): Boolean; la cual recibir en sus parmetros el inicio del rango de opciones y el final del mismo, por ejemplo, viendo un men como los que tiene nuestro programa: Modificar Productos: 1) 2) 3) 4) 5) 6) 7) Todos Segn ID Segn Nombre Comestibles Frutas y verduras Higiene del hogar Higiene personal

9) Volver al Men Principal Opcin >> inicioRango sera '1' y finRango sera '9'. Ahora bien, si son obseravdores deberan preguntarse qu pasa si el usuario ingresa el valor '8'. Pues sera una buena pregunta. Para estos casos debemos modificar nuestro men de modo que todas las opciones sean consecutivas: Modificar Productos: 1) 2) 3) 4) 5) 6) 7) Todos Segn ID Segn Nombre Comestibles Frutas y verduras Higiene del hogar Higiene personal

8) Volver al Men Principal Opcin >>

Estas modificaciones debern hacerlas con todos los mens que hagan falta. Asumiremos siempre que inicioRango<finRango. Finalmente queda por ver el hecho de que la lista de elementos sea variable. Para esto implementaremos un arreglo con tope de la siguiente manera:

Vladimir Rodrguez

132

Programacin estructurada en Pascal


Const N= 5; Type Categorias= (comestibles, frutas_verduras, higiene_h, higiene_p); TNaturales= 1..MAXINT; Elemento= Record Nombre: String; Stock: TNaturales; Precio: Real; Categoria: Categorias; ID: TNaturales; End; Productos= Record Array[1..N] of Elemento; tope: 0..N; End; Como ven, esta definicin no cambia a la anterior en casi nada, simplemente implementa el tipo Productos como un arreglo con tope. De este modo nuestro Men Principal ser as: MEN PRINCIPAL: 1) 2) 3) 4) 5) 6) 7) 8) Opcin: donde cambia la primera opcin, ya que ahora no ingresaremos un nmero de productos preestablecido, sino que podemos ingresar uno o ms; y aadimos dos opciones nuevas. Veamos entonces la opcin 1 de nuestro men: |-----------Producto 1-----------| ID >> 1 Nombre >> Azcar Stock >> 10 Precio >> 50,5 Categoras: (1) (2) (3) (4) Ingresar nuevo producto. Ver lista de productos. Modificar productos. Vender. Buscar. Cantidad de productos ingresados. Eliminar producto. Salir.

Comestibles Frutas y verduras Higiene del hogar Higiene personal

Ingrese la opcin deseada >> 1 Ingresar otro producto (1= SI/2= NO): j ERROR: Dato inesperado, ingrese un dato vlido. Ingresar otro producto (1= SI/2= NO): 1 |-----------Producto 2-----------| ID >> 2 Nombre >> Harina Stock >> 10 Precio >> 42,5 Categoras: (1) Comestibles (2) Frutas y verduras

Vladimir Rodrguez

133

Programacin estructurada en Pascal


(3) Higiene del hogar (4) Higiene personal Ingrese la opcin deseada >> 0 ERROR: Dato inesperado, ingrese un dato vlido. Ingrese la opcin deseada >> 1 Ingresar otro producto (1= SI/2= NO): 2 Con eso volveramos al Men Principal. Si el usuario est en el men principal y selecciona la opcin 1, entonces volveremos al ingreso de productos tal como se vio arriba. Imaginen que ya se han ingresado 5 productos, entonces veramos: |-----------Producto 6-----------| ID >> 6 Nombre >> AzcarImpalpable Stock >> 10 Precio >> 55,5 Categoras: (1) Comestibles (2) Frutas y verduras (3) Higiene del hogar (4) Higiene personal Ingrese la opcin deseada >> 1 Ingresar otro producto (1= SI/2= NO): 2 Siempre debemos saber cuantos productos tenemos en nuestra lista. Veamos ahora la opcin 6: Cantidad de productos ingresados: Simplemente se nos mostrar en pantalla la cantidad de productos en nuestra lista. Por ejemplo: Total de productos: 6 Presione ENTER para volver al Men Principal... Lo ltimo por ver es la opcin Eliminar producto: Se nos mostrar el siguiente men: ELIMINAR PRODUCTO: 1) 2) 3) 4) 5) Eliminar Eliminar Eliminar Eliminar Eliminar segn ID Comestibles Frutas y Verduras Higiene del Hogar Higiene Personal

6) Volver al Men Principal Opcin: Podemos eliminar un elemento determinado dando su ID, o podemos eliminar toda una categora completa para agilizar las cosas. Veamos dos ejemplos: Supongamos que seleccionamos la opcin 1, luego se nos pedir el ID. Supondremos que el usuario ingresa un ID que no existe, lo cual es un error, se pedir de nuevo el dato, tras lo cual el usuario ingresar un ID correcto. Como podrn ver, para no eliminar nada y volver al men principal debe ingresarse la letra M, cualquier otra cosa ser un error. Ingrese el ID del producto a eliminar o M para volver al men principal: 12 ERROR: Dato inesperado, ingrese un dato vlido.

Vladimir Rodrguez

134

Programacin estructurada en Pascal


Ingrese el ID del producto a eliminar o M para volver al Men Principal: 1 ID: 1 Nombre: Azcar Stock: 10 Precio: 50,5 Categora: Comestibles Seguro que desea eliminar este producto (S/N): S Producto eliminado, presione ENTER para volver al Men Principal... Veamos ahora un ejemplo en el que se selecciona la categora comestibles para eliminar los productos: Seguro que desea eliminar la categora comestibles? (S/N): S Eliminados: Azucar Harina Fideos ID: 1 ID: 2 ID: 5

Presione ENTER para volver al Men Principal... Como ven, se mostrar un listado de todos los elementos eliminados. Estarn mostrados en el orden que fueron ingresados. Para cualquiera de estas opciones debern implementar el siguiente procedimiento: PROCEDURE EliminarProducto(VAR Lista: Productos; indice: integer); donde lista ser nuestro listado de elementos e indice ser el lugar de la lista donde est el elemento a eliminar. Cada vez que se elimina un elemento debemos correr todos los siguientes a ese un lugar a la izquierda y reducir el tope un nmero. Veamos una ilustracin:

Producto 1

Producto 2

Producto 3

Producto 4

Producto 5

Vaco

Vaco

5
TOPE= 5

All vemos una lista de elementos donde el arreglo tiene 7 celdas, 5 de las cuales contienen productos, las otras dos no, por lo tanto nuestro tope es 5. En este ejemplo eliminaremos el producto nmero 3, con lo cual nuestro arreglo quedara as.

Producto 1

Producto 2

Producto 4

Producto 5

Vaco

Vaco

Vaco

El producto nmero 3 fue eliminado con lo cual ahora el producto 4 y 5 se corren un lugar hacia la izquierda y el tope se reduce en 1, o sea, TOPE= 4 Producto 4 estaba en la celda 4 pero ahora est en la celda 3, Producto 5 estaba en la celda 5 pero ahora est en la 4, y donde estaba Producto 5 no hay nada que nos interese, por lo tanto corremos nuestro tope hacia la ltima celda que contiene informacin. Nuestro procedimiento debe hacer justamente esta tarea cada vez que se elimina un elemento de nuestra lista. Si por ejemplo se eliminaran todos los Productos menos el Producto 5 entonces quedara as, donde TOPE= 1: Producto 5 Vaco Vaco Vaco Vaco Vaco Vaco

1
Vladimir Rodrguez

7 135

Programacin estructurada en Pascal


Si se eliminara todo, nuestro TOPE sera 0 y nuestro arreglo estara vaco, y lo pongo entre comillas porque en realidad las celdas siguen conteniendo informacin solo que a nosotros no nos importa en absoluto y la tratamos como nula o vaca, de eso se trata la implementacin de Arreglos con Tope. Si se intenta eliminar productos cuando ya no existe nada para eliminar el programa debe darnos el mensaje La lista de elementos est vaca.

Hasta aqu llegamos por ahora con nuestro proyecto. La siguiente parte de este tutorial trata el ltimo tema y, a mi gusto, el ms interesante, con lo cual modificaremos por ltima vez nuestro programa de modo que quede perfecto y utilice solo los recursos que necesita para funcionar, pero ya veremos esto. Deben intentar realizar todo lo que detallo aqu antes de continuar, no importa cuanto tiempo les lleve, cuantas veces se tranquen, si tienen que escribirme a m o buscar ms info en Internet, deben lograr hacerlo. No hay nada aqu que no puedan hacer con lo que saben hasta ahora, es ms, todo est pensado para que lo hagan justamente con estas herramientas. Si han logrado resolver la mayora de los ejercicios anteriores ms este programa, entonces han aprendido lo bsico de la programacin de forma excelente y podrn resolver cualquier tipo de situacin que no requiera estructuras mucho ms complejas que estas que hemos visto ms las que veremos a continuacin. Existe una herramienta de implementacin de funciones llamada RECURSIN, sin embargo no la veremos en esta entrega.

Vladimir Rodrguez

136

Programacin estructurada en Pascal

SEXTA PARTE

Memoria Dinmica: El tipo Puntero Listas Encadenadas Simples

Vladimir Rodrguez

137

Programacin estructurada en Pascal Introduccin:

Hemos llegado al fin al tema ms importante de este tutorial, el que he venido nombrando desde hace tiempo y el que tal vez les haga quemar bastante ms las neuronas, los Punteros. Antes que nada djenme aclarar que el tipo Puntero no tiene nada que ver con el puntero del ratn.... jeje... Bueno, pongmonos serios. Como dije en la introduccin a la tercera parte de este tutorial, todos los tipos que hemos visto hasta ahora son estticos, o sea que una vez declaradas las variables de cierto tipo se asignar en tiempo de compilacin la memoria RAM necesaria para guardar el mayor valor de dicho tipo y mantendremos siempre esa memoria reservada para nuestro uso, la utilicemos o no. Un ejemplo bien sencillo son los arreglos con tope. Declarado un arreglo de N cantidad de celdas, al compilar el programa se dir que reservemos en memoria el espacio suficiente para guardar datos en todas ellas. Supongan que N es igual a 1000 en un arreglo con tope para guardar quin sabe qu cosa; al compilar el programa se asignar memoria para mil celdas aunque usemos solo una o dos, lo cual es un desperdicio. Es aqu donde entra en juego el tipo Punteros, ya que nos permitir pedir memoria en tiempo de ejecucin, tanta como necesitemos, y devolverla cuando queramos. Por eso llamamos a este tema Memoria Dinmica. Utilizando la estructura de los punteros, por ejemplo, podemos hacer que nuestro programa de productos de almacn pida memoria para guardar los datos de un producto cada vez que el usuario ingresa uno nuevo, y liberar dicha memoria cuando se eliminan los productos. Ese tipo de tareas lo haremos con una estructura llamada Listas Encadenadas, pero an nos faltan datos para llegar a ello, as que vallamos all con los punteros.

Vladimir Rodrguez

138

Programacin estructurada en Pascal El tipo Puntero:


Un puntero es un tipo, al igual que un arreglo o un registro, pero es un tipo muy especial ya que hace referencia directa a un lugar especfico de la memoria RAM pero no es parte de ese lugar, o sea, una variable del tipo puntero es entonces un apuntador a un lugar de memoria, una direccin, una flecha o como ustedes quieran visualizarla mejor. Todas las variables de los tipos estticos (todos los que hemos visto hasta el momento) nos referencian el lugar de la memoria en el que estn, por esto son llamadas variables referenciadas y por lo tanto cambiando el valor de la variable cambiamos el valor del lugar de la memoria, sin embargo con un puntero no es as, ya que l apunta a un lugar con el cual podemos hacer lo que sabemos hasta el momento, pero el valor del puntero seguir siendo el mismo porque la direccin de la memoria sigue siendo la misma, o sea que un puntero no apunta al lugar de la memoria en que est, sino a otro totalmente distinto. Tal vez leyendo eso ustedes dirn: Pero ya hemos ledo de flechas y lugares de memoria a los que apuntan, y yo les dir que tienen razn, pero la diferencia ahora es que podemos controlar a esas flechas y adems al lugar al que apuntan. Ya comprendern esto un poco mejor a medida que avancemos. Declaracin: Veamos entonces en un ejemplo como definir el tipo puntero hacia enteros: TYPE MiPuntero= ^integer; Como pueden observar, al tratarse de un tipo debe ir declarado debajo de la palabra reservada TYPE, luego le damos un nombre seguido del signo de igual tal como si fuera un registro, un arreglo u otro tipo definido por nosotros mismos. Luego escribimos el acento circunflejo (^) seguido inmediatamente del tipo al que apuntaremos sin separar por espacios. En este caso hemos definido un tipo puntero llamado MiPuntero que apuntar a datos del tipo integer, o sea, apuntaremos a nmeros enteros. Como en cualquier tipo debemos definir luego una variable de ese tipo para poder trabajar con l. En este ejemplo: VAR puntero1: MiPuntero; Hasta este punto solo tenemos una variable del tipo puntero, o sea una direccin, pero no est inicializada por lo cual no apunta a nada, tiene basura y con ella no se puede trabajar. Cualquier intento de trabajo con un puntero no inicializado terminar probablemente con un error en tiempo de ejecucin lo cual no es para nada recomendable, por lo tanto SIEMPRE INICIALIZEN SUS PUNTEROS, o mejor dicho SIEMPRE INICIALIZEN SUS VARIABLES. Se que ya dije eso antes, pero nunca est de ms recordarlo, aunque pueden verlo en todos y cada uno de los ejemplos de programas en este manual. Entonces lo primero que debemos hacer es inicializar nuestro puntero, y para esto tenemos dos maneras: lo inicializamos de la nada, o sea, pedimos una celda de memoria a la que apuntar para luego poder asignarle valores a esta y trabajar con ella como con cualquier variable; o bien le asignamos la direccin de otro puntero ya inicializado. A diferencia de cualquier tipo, a un puntero no podemos asignarle valores, o sea, no podemos dar una direccin especfica de una celda y decirle apunt para all, excepto si le pasamos la direccin de otro puntero o si le damos el valor de una constante especial, pero esto lo veremos ms adelante. Ahora veamos como inicializar un puntero desde la nada. Otro modo de declarar un puntero es, al igual que con arreglos, de forma annima: VAR puntero1: ^integer; El procedimiento NEW y el operador ^: Bien, un puntero no se inicializa como cualquier variable porque como ya dije no podemos ir y asignar un valor especfico tal y como lo hacemos con los enteros, los caracteres y dems. Simplemente pediremos una celda de memoria y esta se asignar automticamente en funcin de lo que exista disponible. Si se diera el caso en el que no haya suficiente memoria RAM tendramos algn problema, pero esto no suceder para nosotros ya que nuestros programas no usarn casi nada. Para darle un valor inicial a un puntero tenemos que utilizar el procedimiento NEW, el cual simplemente llevar entre parntesis el nombre de nuestra variable puntero. En nuestro ejemplo sera: NEW(puntero1); con lo cual ahora tenemos una celda de memoria asignada para nuestro trabajo. Nuestro puntero tiene una direccin fija, o sea, tiene un valor, pero el lugar de la celda al que apunta contiene basura, tal como sucede con las variables normales. Si definimos una variable del tipo integer y no la inicializamos esta quedar con un valor que depender de nuestro compilador, lo cual no es para nada seguro. Grficamente tenemos lo siguiente:

Vladimir Rodrguez

139

Programacin estructurada en Pascal


Nuestra variable puntero1 apunta hacia un lugar preciso pero no sabemos qu hay all. Ahora bien, si un puntero contiene la direccin de la memoria pero no su valor cmo modificamos lo que existe all? En una variable comn y corriente como las que conocemos, simplemente al escribir su nombre estamos referenciando al lugar de la memoria que ocupa y su contenido, con lo cual podemos acceder a l directamente y modificarlo, mostrarlo en pantalla, asignarle un valor ledo de la entrada estndar o hacer cualquier operacin. Con un puntero podemos hacer lo mismo ya que PASCAL nos da la estructura para trabajar con el valor de la memoria como si fuera una variable referenciada: puntero1^:= 10; De este modo estamos asignando el valor 10 a la celda de memoria, tal como si fuera una variable entera comn. Podemos entonces decir que puntero1^ es el identificador de la variable en esa celda. Lo que intento decir es que del mismo modo que en una declaracin del tipo VAR X: integer; utilizamos al identificador X para trabajar con los valores de la memoria, en una declaracin del tipo VAR X: UnTipoPuntero; utilizamos al identificador X^ para trabajar con el valor de la memoria. De este modo podemos hace con X^ todo lo que se puede hacer con las variables comunes, sea READ, READLN, WRITE, WRITELN, as como tambin podemos utilizarlos en asignaciones, operaciones, comparaciones y dems. Entonces, hay algo que tiene que quedar muy claro. Dado un tipo puntero y una variable X del tipo puntero, una cosa es nombrar a X (el puntero en s) y otra es nombrar a X^ (el lugar al que apunta X). Diremos que X contiene la direccin en la que est X^. Si lo vemos grficamente sera as: En esta figura pueden ver el cdigo PASCAL completo de lo que hemos visto hasta ahora sobre punteros. Creamos el tipo MiPuntero como punteros a enteros, luego declaramos la variable puntero1 de ese tipo, pedimos una celda de memoria para luego poder asignarle el valor entero 10 con lo cual termina nuestro programa. Algo muy pero muy importante es que no pueden hacer referencia a puntero1^ si antes no han solicitado una celda de memoria ya que si nuestro puntero no apunta a ningn lado qu es entonces puntero1^? Como dije antes, trabajar con un puntero no inicializado nos dar un error en tiempo de ejecucin, y no queremos eso jams. Las variables del tipo puntero, a pesar de contener una direccin de memoria, son variables y por tanto su espacio de memoria se asigna en tiempo de compilacin. De que sirven entonces? No es lo mismo mantener esttico el volumen de memoria necesario para almacenar a varios punteros que para almacenar los tipos a los que estos apuntarn. Veamos un ejemplo para que comprendan esto: Supongan la siguiente declaracin: TYPE RegistroPersona= Record Nombre: String; Edad: Integer; Peso: Real; End; Persona= ^RegistroPersona; //Un puntero al registro. VAR pers1: Persona; //Variable del tipo puntero a un registro.

Vladimir Rodrguez

140

Programacin estructurada en Pascal


La variable pers1 es un puntero a un registro, o sea, contendr la direccin de memoria en la que guardar un registro con tres datos, sin embargo pers1 solo guarda una direccin, lo cual es esttico para cualquier tipo de puntero y es infinitamente menor en tamao que lo que se necesita para almacenar un registro. Por lo tanto es mejor mantener un volumen de memoria esttico para almacenar punteros que para almacenar estructuras de datos complejas. Si tengo que almacenar tres registros, es mejor ocupar el espacio de tres punteros que soliciten la memoria cuando haga falta y la liberen luego, que mantener siempre ocupado el espacio para tres registros, los cuales pueden ser enormes. Imaginen un arreglo de registros tal y como usamos en nuestro programa de productos; dicho arreglo es una estructura muy compleja y conlleva mucha memoria no sera mejora administrarla de otra manera? Pues s, y pronto veremos como hacerlo. Ahora vean el siguiente cdigo e intenten darse cuenta de qu saldr en pantalla si ptr1 y ptr2 son punteros a enteros: new(ptr1); new(ptr2); ptr1^ := 12; ptr2^ := ptr1^ + 4; readln(ptr1^); writeln(ptr2^ * ptr1^)

(* suponga que se ingresa 3 *) (* qu despliega? *)

La respuesta correcta es no se sabe, piensen ustedes el por qu.

Alias de variables: Veamos lo siguiente paso a paso: TYPE puntero= ^integer; VAR p1, p2: puntero; Tenemos hasta este momento lo siguiente:

donde ninguna de nuestras variables est inicializada y por lo tanto no podemos hacer nada con ellas. Sigamos entonces y veamos lo que sucede: NEW(p1);

Como pueden ver hemos solicitado un lugar de memoria para p1, o sea lo inicializamos de la nada y le damos su espacio para almacenar un entero; dicho espacio contiene algn valor desconocido (basura). La variable p2 sigue sin inicializar por lo que contiene una direccin que no sirve para nada y que solo nos traer problemas hasta que le demos un valor. Ahora hacemos lo siguiente: p2:= p1 con lo cual obtenemos el siguiente resultado: Hemos asignado a p2 el valor de p1, o sea, le hemos dicho a p2 que apunte hacia la misma celda que p1. Cuando dos o ms punteros apuntan a una misma celda decimos que son alias. Esto puede ser muy til ya pero a la vez es muy peligroso ya que al modificar la celda de uno modificamos la del otro, tal como sucede con el pasaje de parmetros por referencia. Ahora veamos una asignacin similar pero muy diferente:

Vladimir Rodrguez

141

Programacin estructurada en Pascal


Sean p1 y p2 punteros a caracteres (char), dado el siguiente fragmento de cdigo tenemos la siguiente situacin: New(p1); New(p2); p1^:= 'c'; p2^:= 'j';

Noten ahora la diferencia entre estas dos asignaciones suponiendo que las mismas son escritas luego del cdigo anterior, o sea, o escribimos una o la otra, no una seguida de la otra: p1^:=p2^ p1:=p2

Como podrn observar, en el primer caso hemos copiado el contenido de la celda de p2 en la de p1 con lo cual ambas variables (p1^ y p2^) valen lo mismo. Esto es igual a hacer una asignacin del tipo X:= Y siendo X e Y variables de un mismo tipo. Ahora vean el segundo caso donde en vez de usar p1^ y p2^ usamos p1 y p2 directamente. Como podrn observar p1 pasa a apuntar al mismo lugar que p2 transformndose ambos en alias, sin embargo la celda a la que apuntaba p1 originalmente queda sin nadie que la apunte por lo cual ya no es posible acceder a ella, pero sigue conteniendo su valor guardado y por tanto sigue ocupada, no ha sido liberada. La forma correcta de hacer esto habra sido liberar primero la celda de p1 de modo que este quede indefinido y luego hacer la asignacin p1:= p2. Este tipo de errores es muy comn y pronto veremos alguno ms. El trabajo con la memoria dinmica requiere muchsima atencin para hacerlo bien y controlar todo correctamente. Por eso muchos programadores sostienen que es mejor tener un sistema que se encargue de liberar la memoria automticamente cada cierto tiempo como lo hace Java y otros no. Yo me inclino por los que no, pero es una simple opinin personal. Un uso incorrecto de NEW: Si hacemos NEW de un puntero ya inicializado estaremos pidiendo un nuevo espacio de memoria para l, con lo cual apuntaremos al nuevo lugar y dejaremos el otro en la nada. Sea p un puntero a caracteres: NEW(p); p^:= 'a'; Ahora, luego de estas instrucciones hacemos NEW(p);

Como vern, al hacer NEW de un puntero obtenemos un nuevo lugar en la memoria sin importar lo que hubiera antes. De este modo si el puntero estaba indefinido lo definimos, y si ya estaba definido lo redefinimos sin importar lo que haba antes. De este modo, si ya tenamos un lugar de la memoria asignado, obtenemos uno nuevo a costa de abandonar el otro pero dejndolo ah, con o sin valor asignado, pero no liberado y sin posibilidad de volver a acceder a l. Tengan esto siempre en mente: NEW nos da un nuevo espacio de memoria y nos apunta hacia l, no importa lo que haya sucedido hasta el momento, NEW define nuevamente de cero al puntero y ya. Si hacemos treinta NEW seguidos de un mismo puntero habremos creado treinta lugares de memoria pero solo apuntaremos al ltimo creado y los otros veintinueve quedarn en nuestra memoria, ocupando lugar, pero sin posibilidad de ser accedidos o usados. Por suerte los sistemas operativos se encargan de liberar la memoria mal usada.

Vladimir Rodrguez

142

Programacin estructurada en Pascal


El procedimiento DISPOSE: As como se nos hace necesario solicitar memoria cuando haga falta, se nos har necesario liberarla cuando ya no la necesitemos. Hemos visto que, dado un puntero a algn tipo determinado, el procedimiento NEW nos asigna una porcin de memoria y su direccin para que podamos acceder a ella. Por ejemplo, dado un puntero p a cualquier tipo, si hacemos NEW(p) obtenemos nuestra porcin de memoria a la cual llamaremos p^ y su direccin quedar almacenada en p. As como es de fcil solicitar memoria lo es el liberarla. Teniendo un puntero ya inicializado, utilizamos el procedimiento DISPOSE para liberar su porcin de memoria, por ejemplo, sea el mismo puntero p a algn tipo especfico y estando p ya inicializado utilizamos: DISPOSE(p); De este modo la porcin de memoria se libera para que el sistema pueda utilizarla y p queda indefinido, o sea, queda como si nunca lo hubiramos inicializado. Vimos anteriormente que si hacemos sucesivos NEW de un mismo puntero vamos solicitando memoria en cada uno, pero vamos dejando perdidas las porciones de memoria de los NEW anteriores quedndonos solo con la del ltimo, lo cual es un desperdicio porque el sistema cree que las porciones no referenciadas estn igualmente siendo utilizadas y eso no es as. Ahora qu pasa si hacemos sucesivos DISPOSE de un mismo puntero? Copien este cdigo en su compilador y observen el resultado: PROGRAM SucesivosDispose; TYPE TipoPuntero= ^Char; VAR puntero: TipoPuntero; BEGIN writeln('Presione ENTER para solicitar memoria al sistema'); readln; new(puntero); writeln('Hemos solicitado memoria al sistema.'); writeln('Presione ENTER para liberar la memoria solicitada.'); readln; dispose(puntero); writeln('Hemos liberado la memoria solicitada.'); writeln('Presione ENTER para liberar nuevamente.'); readln; dispose(puntero); writeln('Todo ha salido bien, presione ENTER para salir.'); readln; END.

Como vern, primero solicitamos memoria inicializando puntero mediante NEW con lo cual obtenemos nuestro espacio para almacenar un carcter as como la direccin de ese espacio. Luego liberamos ese espacio mediante DISPOSE con lo cual la informacin contenida en l se pierde, o sea, deja de existir puntero^ y puntero queda indefinido, o sea, su direccin es cualquier cosa. Luego nuevamente intentamos liberar memoria, sin embargo puntero no apunta a nada especfico, contiene una direccin errnea porque est indefinido, por lo tanto no podemos liberar memoria de un lugar al que no podemos llegar lo cual genera un error en tiempo de ejecucin y nuestro programa se cerrar abruptamente (si no es as depende del compilador, sin embargo dejar eso a suerte es un error en la metodologa de programacin). Como ven, utilizar DISPOSE con punteros no inicializados es un error grave y hay que tener mucho cuidado a la hora de utilizar este procedimiento. Por eso es complicado administrar bien la memoria que utiliza el programa, ms an cuando la cosa se vuelve compleja. Ahora que saben liberar memoria pueden hacer de forma correcta lo que seal como error anteriormente, o sea, cuando tenemos dos punteros inicializados pero queremos transformarlos en alias, o sea, que ambos apunten a lo mismo, debemos primero liberar la memoria de uno de ellos y luego cambiar su direccin, de este modo no habr porciones de memoria que se queden perdidas en el espacio:

Vladimir Rodrguez

143

Programacin estructurada en Pascal

Nota: Sea un puntero p hacia cualquier tipo especfico, si p no est inicializado no podemos referenciar a p^ porque tal lugar de memoria no existe. Hacerlo causa un error en tiempo de ejecucin. De este modo, referenciar al lugar que apunta un puntero luego de un procedimiento DISPOSE es un error de programacin. Seguiremos con un ltimo concepto para luego ver algunos ejercicios antes de continuar. El siguiente tema luego de esto ser Listas Encadenadas, lo cual est basado en el mero uso de punteros. UN ERROR COMN: Alias y DISPOSE: Supongan que tenemos dos punteros, p y q, apuntando a una misma celda, o sea, p y q son alias:

Si hacemos DISPOSE(p) qu pasa?

Ahora q qued tambin indefinida porque la porcin de memoria a la que apuntaba ya no existe. Tengan mucho cuidado con este tipo de situaciones.

El puntero nulo, la constante NIL: Hemos visto que una variable de un tipo puntero es una variable que contiene una direccin hacia una porcin de memoria en la que se almacenar un tipo de dato especificado. Vimos tambin que no es posible asignar valores especficos a un puntero excepto si le pasamos el valor de otro puntero ya inicializado anteriormente. Existe, sin embargo, una constante general para cualquier tipo de puntero la cual contiene el valor nulo y que podemos asignarle a cualquiera de nuestros punteros; esta constante es llamada NIL. Sea p un puntero a un tipo cualquiera, podemos hacer:

Vladimir Rodrguez

144

Programacin estructurada en Pascal


p:= NIL; en cualquier momento. NIL es la forma correcta de decir que un puntero no est apuntando a nada, que es nulo, lo cual no es lo mismo que decir que no est inicializado. Un puntero que apunta a NIL no tiene memoria asignada, pero tiene un valor correcto, asimismo, como no tiene celda asignada no podemos acceder a ella mediante el operador ^, o sea, para nuestro p, si p=NIL no podemos acceder a p^ porque no existe, si lo hacemos tendremos un error en tiempo de ejecucin, por eso siempre que estemos trabajando en situaciones donde un puntero pueda valer NIL debemos preguntarlo primero. Esto es posible porque NIL admite comparaciones, o sea, si tenemos un puntero p podemos hacer por ejemplo:

IF p=NIL THEN...
o por ejemplo

IF p<>NIL THEN...
o en cualquier cosa ya que podemos utilizarlo como condicin:

WHILE p<>NIL DO... REPEAT ...UNTIL p=NIL


etc.

Asignar el valor NIL a un puntero ya inicializado sin antes hacer DISPOSE de l es un error ya que cambiaremos la direccin del puntero sin antes liberar la memoria con lo cual quedara esta perdida en la nada. Es el mismo caso que asignar a un puntero ya inicializado el valor de otro puntero sin antes liberar sus memoria. IMPORTANTE: Siempre que vayan a asignar a un puntero ya inicializado algn valor deben liberar la memoria asignada para l. Hacer DISPOSE de un puntero NIL es un error de programacin, puede no causar problemas, pero no debe hacerse jams. Para qu sirve el valor NIL? De qu sirve decir que un puntero no apunta a nada? Pues lo veremos dentro de poco, primero realicen estos ejercicios simples antes de continuar. Ejercicio1: a) Determinen cules de las siguientes proposiciones son vlidas:

new(apun1) new(apun1^) apun1 := apun3 apun2^ := apun2^ + apun1^ apun1 := NIL apun4^ := NIL writeln(apun2, apun3) read(apun1^, apun4^) b) Determinen cules de las siguientes proposiciones son vlidas:

1.apun1 := NIL 2.apun2 := new(apun1) 3.dispose(apun3) 4.apun3^ := NIL 5.apun3 := apun4 AND (apun3 6.apun4^ := NIL

= NIL)

Vladimir Rodrguez

145

Programacin estructurada en Pascal


Ejercicio 2: 1. Consideren las declaraciones que se hicieron en el Ejercicio 1. Determinen la salida que produce el siguiente cdigo: new(apun1); new(apun2); new(apun3); apun2 := apun1; apun1^ := 2; apun2^ := 3; apun3^ := A; writeln(apun1^, apun2^, apun3^) 2. Tiene algn error el siguiente cdigo? Supongan que apun1 es una variable de apuntador que hace referencia a una variable entera. new(apun1); read(apun1^); writeln(apun1^); dispose(apun1); writeln(apun1^)

Ejercicio 3: Consideren las declaraciones realizadas en el Ejercicio 1, determinen la salida del siguiente cdigo: new(apun3); new(apun1); apun3^ := Z; apun2 := NIL; apun4 := NIL; IF (apun3 <> NIL) AND (apun2 = NIL) THEN writeln (Cdigo A); IF apun3^ = Z THEN writeln (Cdigo Z) ELSE writeln (Cdigo X)

Ejercicio 4 Dado el siguiente cdigo en Pascal Type TipoVehiculo = (barco, camion); Transporte = record capacidad : INTEGER; case vehiculo : TipoVehiculo of barco : (habitaciones : INTEGER); camion : (); end; var a, b, c : ^Transporte; begin new(a); a^.capacidad := 30; a^.vehiculo := barco; a^.habitaciones := 4;

Vladimir Rodrguez

146

Programacin estructurada en Pascal

new(b); b^.capacidad := 4; b^.vehiculo := camion; new(c); c^.capacidad := 5; c^.vehiculo := camion; end. 1- Cul de las siguientes figuras representa el estado de la memoria? (tengan en cuenta que se omiten los nombres y valores de algunos campos para no recargar el dibujo).

2- Dada la instruccin: b := c 2.1 Cul de las siguientes figuras representa el estado de la memoria posterior a la instruccin? (tengan en cuenta que en las figuras se omiten los nombres y valores de algunos campos para no recargar el dibujo).

2.2 Sera correcto hacer dispose(b) antes de la instruccin? Justifiquen. 3- Dada la instruccin b^ := c^ 3.1 Dibujen el estado de la memoria posterior a la instruccin. 3.2 Qu valor tiene b^.capacidad? 3.3 Teniendo en cuenta que se quiere mantener las referencias a los componentes referenciados sera correcto hacer dispose(c ) despus de la instruccin? Justifiquen.

Realicen todos estos ejercicios antes de continuar. Pregntenme acerca de todo aquello que les provoque dudas, les responder a la brevedad. Si no logran comprender estos conceptos no podrn trabajar con lo que viene a continuacin. Adelante!!!

Vladimir Rodrguez

147

Programacin estructurada en Pascal Listas encadenadas simples:


Es aqu donde utilizaremos el verdadero potencial de los punteros. No aprenderemos en s nada nuevo ya que en lo que a lenguaje refiere hemos aprendido todo a lo que apunta el manual, esto es simplemente una implementacin de una herramienta ya conocida, una implementacin que probablemente no se les ocurrira por s mismos y es por esto que en las universidades y cursos de programacin se ensea de forma especfica. De forma sencilla, una lista encadenada simple es un listado de varios elementos de un mismo tipo donde existe uno que es el primero y uno que es el ltimo, tal como en los arreglos. La diferencia es que las listas son dinmicas y pueden aumentar o disminuir de tamao llegando incluso a ser vacas, ocupando solo la memoria que necesitan para existir en el momento preciso. A forma de esquema, tenemos un primer elemento que, adems de contener todos los datos que sean, nos dir donde est el segundo elemento, que nos dir donde est el tercero, que nos dir donde esta el cuarto, y as sucesivamente hasta llegar a uno que nos diga Ya no hay ms elementos.

All pueden ver un dibujo sencillo de lo que sera una lista encadenada. Cada elemento contiene lo que tiene que contener y adems nos dice donde est el elemento siguiente a l en la lista, hasta que algn elemento nos diga que ya no existe nada ms despus de l con lo cual diremos que estamos al final de la lista. Veamos como aplicar este concepto en PASCAL. Para empezar diremos que cada elemento de una lista es un nodo, por lo tanto una lista puede ser vaca (cuando no existe nodo alguno), contener un nodo o varios. La gracia de esto ser poder modificar los nodos, quitarlos, agregarlos y moverlos. En este primer ejemplo definiremos lo que es un nodo de lo que ser un alista de nmeros enteros. Pongan mucha atencin para comprender esto porque causa confusin y a veces cuesta entender lo que se est escribiendo: TYPE Lista= ^NodoLista; NodoLista= Record numero: integer; siguiente: Lista; End; Veamos: Definimos el tipo Lista como punteros hacia el tipo NodoLista, el cual declaramos ms abajo como un registro de dos campos, uno del tipo entero que ser nuestra informacin, y otro con un puntero del tipo Lista, o sea, un puntero que apuntar a elementos del tipo NodoLista. Al tener un puntero del tipo Lista, estaremos apuntando a un registro que dentro de l tendr, adems de un nmero entero, otro puntero del tipo Lista, y as por cada uno. Cada elemento del tipo Lista podr apuntar a otro con la misma estructura. Veamos esto en un dibujo:

Vladimir Rodrguez

148

Programacin estructurada en Pascal


Como ven, cada elemento del tipo Lista tiene un puntero que apunta a una estructura del tipo Lista por lo cual podemos ir repitiendo esa estructura tanto como queramos, donde cada elemento tiene el puntero hacia el siguiente quedando todos encadenados. De este modo, para tener una lista simplemente necesito el puntero hacia el primer elemento ya que a partir de este podr obtener el siguiente y, recorriendo uno a uno, puedo ver la lista completa. Siempre para dar una lista debe darse el puntero hacia el primer elemento. Dado este sistema, debemos recorrer siempre las listas de forma secuencial, elemento a elemento, ya que no podemos ir directamente a un nodo especfico. Por ejemplo, en una lista de 10 elementos no puedo ir al elemento nmero 5 sin antes recorrer los 4 anteriores. Esto deriva en problemas de eficiencia y metodologas del uso de listas para solucionarlos, pero no los veremos aqu ya que lo importante ahora es saber trabajar con ellas. Crearemos, dada la estructura anterior, una lista de tres nodos, guardando el nmero 10 den cada uno: 1 PROGRAM PrimeraLista; 2 3 TYPE 4 Lista= ^NodoLista; 5 6 NodoLista= Record 7 numero: integer; 8 siguiente: Lista; 9 End; 10 11 VAR 12 MiLista, i: Lista; 13 14 BEGIN 15 New(MiLista); //Creo el primer elemento de la lista. 16 i:= MiLista; //Utilizo un puntero alternativo para iterar. 16 i^.numero:= 10; 17 18 New(i^.siguiente); //Creo el segundo elemento de la lista. 19 i:= i^.siguiente; //Ahora i apunta al segundo elemento de la lista. 20 i^.numero:= 10; 21 22 New(i^.siguiente); //Creo el tercer elemento de la lista. 23 i:= i^.siguiente; //Ahora i apunta al tercer elemento de la lista. 24 i^.numero:= 10; 25 END. Analicemos este cdigo un poco; tengan en cuenta que lo he hecho as para que vean todo, luego lo har de la forma correcta. En la lnea 15 invocamos a NEW para que la variable puntero MiLista obtenga un lugar de memoria para almacenar a un registro NodoLista: MiLista obtiene la direccin de un registro NodoLista y apunta hacia all. Dicho registro tendr a priori un nmero entero cualquiera en su campo numero y un puntero no inicializado en su campo siguiente.

En la lnea 16 utilizo un puntero adicional i para apuntar tambin al primer elemento de la lista transformando a MiLista y a i en alias:

En la lnea 18 solicito el espacio necesario para alojar a un nuevo elemento. El puntero i^.siguiente es del tipo Lista, por lo tanto la sentencia New(i^.siguiente) crear un nuevo registro y nos dar su direccin de memoria:

Vladimir Rodrguez

149

Programacin estructurada en Pascal

En la lnea 19 hago que i apunte al elemento creado recientemente:

En la lnea 20 asigno el valor 10 al nuevo elemento:

En la lnea 22 creo el tercer elemento del mismo modo que fue hecho para crear el segundo. Luego hago que i apunte hacia dicho elemento para asignarle el valor 10 tal como hice anteriormente:

De este modo he logrado construir una lista de tres nodos, cada uno con el valor 10, donde el puntero MiLista apunta al primero de ellos y todos estn encadenados; as, solo obteniendo la direccin de MiLista puedo recorrer todos los nodos uno por uno. Veamos ahora un cdigo que hace lo mismo pero mediante un FOR que iterar tres veces. Este cdigo es el ms correcto ya que ser igual de largo para crear tres nodos que para crear cien comprenden?:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 PROGRAM PrimeraLista; TYPE Lista= ^NodoLista; NodoLista= Record numero: integer; siguiente: Lista; End; VAR MiLista, i: Lista; j: integer; //Un iterador entero para el FOR.

BEGIN New(MiLista); For j:= 1 to 3 do //Crear tres nodos. begin If j=1 then i:=MiLista else new(i^.siguiente); If j<>1 then i:= i^.siguiente; i^.numero:= 10; end; END.

El anlisis de este cdigo les queda de tarea para ustedes.

Vladimir Rodrguez

150

Programacin estructurada en Pascal


Lista vaca: Dije hoy por ah que un lista puede ser vaca o puede contener uno o ms elementos, lo cual es totalmente cierto. Entonces, diremos que una lista es vaca cuando el puntero al primer elemento vale NIL. Por ejemplo, para la estructura anterior si MiLista= NIL diremos que la lista de nmero es vaca. Aunque ya haba hablado del valor NIL para un puntero, no haba dibujado su representacin grfica. Como pueden observar all, no dibuj una flecha, sino un fin abrupto representado por lneas, eso significa NIL, un puntero que no apunta a nada, lo cual es muy distinto a un puntero indefinido. Puedo preguntar si un puntero es NIL mediante una comparacin, pero no puedo saber si es indefinido mediante ningn tipo de sentencia del lenguaje.

Fin de lista: En la primera lista que hemos visto aqu creamos tres nodos. Ahora haremos un pequeo programa que cree tantos nodos como el usuario quiera y a cada uno le asigne el nmero que el usuario quiere. Al terminar nos dir cuantos nodos hemos creado. Asumimos en todo momento que el usuario siempre ingresa informacin correcta: PROGRAM PrimeraLista; USES crt; TYPE Lista= ^NodoLista; NodoLista= Record numero: integer; siguiente: Lista; End; VAR MiLista, i: Lista; j: integer; //Un iterador entero para el FOR. opcion: char; //Para leer opciones de teclado. BEGIN //En esta seccin de cdigo solo mostramos opciones al usuario, creando //la lista vaca si el usuario dice que SI. // //----------------------------------------------------------------------clrscr; write('Desea crear una lista de nmeros enteros? S/N: '); readln(opcion); j:= 0; //Simplemente damos opciones de inicio al usuario. Case opcion of 'S': begin MiLista:= NIL; writeln('Hemos creado una lista vaca.'); writeln; end; 'N': begin write('Presione ENTER para salir...'); readln; exit; end; End;//Fin del CASE OF. {Crearemos tantos nodos como quiera el usuario. Cada vez que elija la opcin 1 crearemos un nuevo nodo y leeremos un nmero de la entrada estndar. Terminaremos cuando el usuario lo desee. De este modo la lista ser de un largo totalmente aleatorio en cada ejecucin} //-----------------------------------------------------------------------

Vladimir Rodrguez

151

Programacin estructurada en Pascal


Repeat //Mostramos las opciones al usuario clrscr; writeln('LISTA DE NMEROS: '); writeln; writeln('1) Agregar nuevo nmero a la lista'); writeln('2) No agregar ms nmeros'); writeln; write('Opcin: '); readln(opcion); {Si la opcin leda es 1 creo el nodo correspondiente y hago que i apunte a dicho nodo. Vean que discrimino mediante un IF si la lista es vaca y si no lo es. Al final leo el nmero directo sobre el nodo para luego sumar 1 a mi contador j.} Case opcion of '1': begin clrscr; write('Nmero: '); If MiLista=NIL then begin New(MiLista); i:= MiLista; end else begin new(i^.siguiente); i:= i^.siguiente; end; readln(i^.numero); j:= j+1; end; '2': writeln('No se ingresarn ms nmeros.'); end; Until opcion='2'; //Terminado el bucle del REPEAT mostramos la informacin al usuario y ya. clrscr; writeln('Se han agregado ',j,' nmeros.'); write('Presione ENTER para salir.'); END. No he numerado las lneas de este cdigo porque no lo analizare, los comentarios son lo suficientemente descriptivos como para que ustedes puedan comprender lo que se est haciendo, adems de que todo ha sido explicado con anterioridad. No continen hasta no comprender este cdigo. Para qu este programa? Qu tiene que ver con el fin de una lista? Bueno, lo que hemos hecho aqu es crear una lista de largo aleatorio, o sea, crearemos tantos nodos como el usuario quiera en el momento, por lo tanto nunca es posible saber cuantos elementos tendremos. Entonces, qu pasa si ahora queremos mostrar los elementos de la lista? Debemos recorrer uno a uno hasta llegar al final de la misma, pero no sabemos hasta donde recorrer. Es cierto que en este caso hemos contabilizado los nodos creados por lo cual podramos iterar tantas veces como diga nuestra variable j, sin embargo esa no es la forma correcta de hacerlo porque en general, los programas que trabajan listas no van contabilizando lo que crean ya que la complejidad a la que se enfrentan no lo permite y traera muchsimos problemas, sobretodo al tener que utilizar herramientas como la recursin, que, aunque en este manual no la aprenderemos, es importante que aprendan a trabajar de forma correcta desde el principio. No puedo explicitarles aqu la importancia de esto ya que no es a lo que apunta este manual. Normalmente los programas trabajan con mdulos independientes, o sea, partes de cdigo independientes entre s donde cada una est en archivos diferentes, y luego existe un archivo principal que se encarga de enlazar (hacer link o linkear) todos los archivos independientes. De este modo el paso de informacin entre un mdulo y otro se vuelve complejo y cuanto menos variables y estructuras existan en este pasaje hacen que la programacin sea ms sencilla, as como el mantenimiento y la actualizacin de los programas. En nuestro prximo manual, donde pasaremos al lenguaje MODULA-2, que es un PASCAL un tanto ms avanzado y orientado a la modularizacin de programas, casi a la programacin orientada a objetos, aprendern estas cosas y podrn hacer programas mucho ms complejos, como pequeos editores de texto y dems. Veamos entonces cmo marcar el final de una lista de manera correcta.

Vladimir Rodrguez

152

Programacin estructurada en Pascal


Es simple. Cada nodo tiene un puntero que apunta al siguiente elemento de la lista, el ltimo elemento simplemente apuntar a NIL y ya, con eso diremos que la lista termin y con eso podremos crear algoritmos muy eficientes en el tratamiento de listas encadenadas.

Veamos, de forma genrica, ejemplos de cdigos para el trabajo habitual con listas encadenadas, o sea, contabilizar sus elementos, agregar un elemento al principio, agregar un elemento al final, buscar un elemento, borrar el primero, borrar la lista completa:

Largo de una lista:

function largo(l: lista): integer; var contador: integer; p: lista; begin contador:= 0; p:= l; while p <> nil do begin contador:= contador + 1; p:= p^.siguiente; (* avanzar a la siguiente celda *) end; largo:= contador; end;
Bsqueda de un elemento:

var

function pertenece(elem: T; l: lista): boolean;

p: lista;
begin p:= l; (* notar: evaluacin por circuito corto *) while (p <> nil) and (p^.elemento <> elem) do p:= p^.siguiente;

pertenece:= (p <> nil);


end;
Como ven en los comentarios, notar la evaluacin por circuito corto. Si no lo recuerdan, significa que en una condicin AND, la parte de la izquierda se cumple entonces verificamos la parte de la derecha y en caso de que ambas sean ciertas el AND es cierto (TRUE). Si la condicin de la izquierda es falsa entonces ni siquiera verificamos la de la derecha. En este caso, si la condicin de la derecha es falsa significa que p=NIL por lo tanto, si quisiramos verificar la segunda parte tendramos que acceder a p^, lo cual es un error porque un puntero NIL no apunta a nada. Agregar elemento al principio:

procedure agregar_al_principio(var l: lista; elem: T); var p : lista; begin new(p); (*crear nueva celda*) p^.elemento:= elem; (*cargar el elemento*)

Vladimir Rodrguez

153

Programacin estructurada en Pascal


(* ajuste de punteros *) p^.siguiente:= l; l:= p; end;
Agregar elemento al final:

procedure agregar_al_final(var l: lista; elem: T); var p,q : lista; begin new(p); p^.elemento:= elem; p^.siguiente:= nil;

(*crear nueva celda*) (*cargar el elemento*) (*es el ltimo*)

if l = nil then l:= p else begin (*busco el ltimo de l*) q:= l; while q^.siguiente <> nil do q:= q^.siguiente; (*engancho p a continuacion del ltimo*) q^.siguiente:= p;

end; end;

Borrar el primer elemento de una lista no vaca:

procedure borrar_primero(var l: lista); var p: lista; begin p:= l; l:= l^.siguiente; dispose(p); end;

Borrar una lista completa:

Para liberar todo el espacio ocupado por una lista es necesario liberar celda por celda.
procedure borrar_lista(l: lista); var p: lista; begin while l <> nil do begin p:= l; l:= l^.siguiente; dispose(p); end; end;

Vladimir Rodrguez

154

Programacin estructurada en Pascal

Continuemos ahora entonces con los ejercicios acerca de punteros, estos estn orientados a las listas: Ejercicio 5: Dado el siguiente cdigo que permite crear una lista encadenada: TYPE apuntador = ^registro; registro = RECORD dato : ...; (* integer, char, real, ... *) sigreg : apuntador; END; VAR apuntaInic : apuntador; apuntaActual : apuntador; indice : integer; BEGIN new(apuntaInic); apuntaActual := apuntaInic; FOR indice := 1 TO 3 DO BEGIN new(apuntaActual^.sigreg); apuntaActual := apuntaActual^.sigreg END; apuntaActual^.sigreg := NIL; END. Cmo modificara el cdigo anterior si se desea, mediante la inclusin de una tercera variable de tipo apuntador, apuntar al ltimo registro de la lista? Suponiendo que el tipo del campo dato en el registro definido anteriormente es de tipo char, escriban un procedimiento en Pascal llamado Buscar que exhiba un mensaje que indique si un valor de tipo char se encuentra o no en la lista. El cabezal del procedimiento es el siguiente: procedure Buscar(c : char; apuntaInic : apuntador) donde c es el char a buscar y apuntaInic es la referencia del comienzo de la lista. Ejercicio 6: 1.Definan un tipo llamado ListEnt, el cual representa una lista encadenada de enteros. 2. Escribir un procedimiento en Pascal que permita insertar un entero al principio de la lista encadenada. El cabezal del procedimiento es el siguiente: Procedure InsertarPrincipio(valor: integer; VAR lista: ListEnt); 3. Escribir un procedimiento en Pascal que permita eliminar el primer elemento de una lista encadenada. El cabezal del procedimiento es el siguiente: procedure EliminarPrincipio (VAR lista: ListEnt);

Ejercicio 7: Dada la siguiente definicin: Type ListChar = ^registro; registro = RECORD campo: char; siguiente : ListChar END;

Vladimir Rodrguez

155

Programacin estructurada en Pascal


1. Escribir una funcin en Pascal que permita insertar un carcter al final de una lista encadenada de caracteres. Ponga especial atencin en no modificar la lista con la cual se invoca a la funcin, sino que se debe copiar toda la lista, y operar sobre la copia. El cabezal de la funcin es el siguiente: function InsertarUltimo (valor :char; lista: ListChar):ListChar; 2. Escribir un procedimiento en Pascal que permita eliminar los primeros cant caracteres (siendo cant una variable dada, mayor o igual a cero) de una lista encadenada de caracteres. El cabezal del procedimiento es el siguiente: procedure DescartarComienzo(cant : integer; VAR lista: ListChar); 3. Escribir una funcin en Pascal que permita obtener, a partir de una lista de caracteres, otra lista con los caracteres que se encuentran entre la posicin indBase e indSup de la lista original (siendo indBase e indSup nmeros enteros mayores o iguales a cero). El cabezal de dicha funcin es el siguiente: function SubCadena (indBase, indSup : integer; lista : ListChar) : ListChar;

BASE PRODUCTOS Parte 3 Nuestro programa seguir haciendo las mismas cosas que en su segunda parte solo que esta vez utilizar la estructura de listas encadenadas para almacenar los elementos de modo que solo utilizar la memoria necesaria para la cantidad de productos almacenados en el momento. Ser tarea de ustedes modificar los cabezales de los procedimientos y las funciones que utilizaban la estructura del arreglo con tope para trabajar con la lista de elementos as como es tarea de ustedes modificar la declaracin de los tipos principales del programa. No necesitan trabajar con listas para corregir errores de la entrada estandar, solo quiero que lo hagan con la lista de productos. Si necesitaran que yo les enve los cabezales de todos los subprogramas no tendr problema en hacerlo ya que por lo general es lo que se hace, sin embargo ser un buen ejercicio para ustedes el tener que pensarlos.

Vladimir Rodrguez

156

Programacin estructurada en Pascal


UN LTIMO PRYECTO:

Les propondr aqu el trabajo con lo que fue la segunda tarea de Programacin 1 en la Facultad de Ingeniera donde estudio. Estos proyectos estn diseados para que apliquen todo lo dado aqu y para que piensen de forma estructurada, la misma forma que he enseado a lo largo de este manual. Es de alto nivel pero podrn hacerla, yo estar abierto a que pregunten todas y cada una de las dudas que tengan al respecto ya que por lo general estos trabajos se acompaan con alguna clase de consulta. Le dar aqu la letra tal y como fue dada a los estudiantes incluyendo hasta las reglas de no copiar y dems, mucha suerte. Espero que lancen a realizar esto: Deben leer todo antes de continuar, ya que luego de la letra del problema existen las instrucciones para implementarlo ya que se les brindar un archivo con el cdigo ya escrito para la interfaz grfica y un archivo con el cual debern trabajar ustedes creando el motor del juego. Aqu ven un ejemplo de un programa donde un archivo se encarga de realizar la interfaz grfica y otro de hacer las tareas del programa, luego ambos trabajan juntos. 1. Introduccin Este documento presenta el problema que deber resolverse para la aprobacin de la segunda tarea del laboratorio del curso 2010. Se presenta informacin acerca de: normas, recursos, plazos, una presentacin general del problema, las especificaciones del mismo, ejemplos de ejecucin y la forma de entrega.

2. Informacin general El estudiante que no respete alguna de las consideraciones que siguen corre el riesgo de que su trabajo sea invalidado, con la consiguiente prdida del curso. Compilador Todos los programas deben ser compatibles con el compilador del curso (Free Pascal). No se aceptarn como vlidas aquellas tareas que pudieran funcionar con algn otro compilador Pascal, pero no funcionen con Free Pascal, versin 2.2.2 para windows. Grupos Esta tarea se deber realizar en forma individual. Para todas las tareas rige el Reglamento del Instituto de Computacin ante Instancias de No Individualidad en los Laboratorios. A continuacin se adjunta un fragmento del mismo; ante cualquier duda se recomienda leer el documento completo (http://www.fing.edu.uy/inco/cursos/prog1/pm/field.php/Laboratorio/NoIndividuali dad)

Los laboratorios deben ser realizados nicamente por los integrantes del grupo establecido La realizacin de los laboratorios es estrictamente individual, sea a nivel unipersonal en el primer caso, o del grupo establecido en el segundo. Se entiende que compartir total o parcialmente cualquier actividad del laboratorio atenta contra la integridad del estudiante universitario y de su formacin, y por lo tanto constituye una falta grave. Especficamente no es posible compartir por ninguna va entre integrantes de grupos distintos las tareas de codificacin, digitacin, compilacin, depuracin y documentacin de los programas u objetos (o entregas) del laboratorio. Adems de que no se pueden compartir actividades del laboratorio, no se pueden compartir los productos de las mismas. Cada grupo es responsable de su trabajo de laboratorio y de que el mismo sea individual, independientemente de las causas que pudiesen originar la no individualidad. A modo de ejemplo y sin ser exhaustivos: utilizacin de cdigo realizado en cursos anteriores (por otros estudiantes) u otros cursos, perder el cdigo, olvidarse del cdigo en lugares accesibles a otros estudiantes, prestar el cdigo o dejar que el mismo sea copiado por otros estudiantes, dejar la terminal con el usuario abierto al retirarse, enviarse cdigo por mail, utilizar cdigo Vladimir Rodrguez

157

Programacin estructurada en Pascal


suministrado por terceros, etc. Asimismo se prohbe el envo de cdigo al grupo de noticias del curso, dado que el mismo ser considerado como una forma de compartir cdigo y ser sancionado de la manera ms severa posible.
Forma de entrega Las entregas se realizarn por la web. Para ello se deber acceder a un sitio destinado a tal fin y seguir los pasos que se explicarn en la pgina correspondiente. Esta pgina estar disponible cuando comience el plazo de entrega. Fecha de Entrega Se debe entregar desde el 4/11 al 10/11. El plazo vence el 10/11 a las 12 de la noche.

3. Presentacin 3.1 Juego Iguales Iguales es un juego tipo puzle. El objetivo es eliminar fichas obteniendo la mayor cantidad de puntos posible. Las fichas que estn adyacentes las unas de las otras se eliminan como un bloque. Las dems fichas se colapsan para rellenar los huecos vacos y se forman nuevos bloques. No se puede eliminar fichas que no estn en un bloque.

El tablero se inicia como una rejilla llena de fichas. Habr cuatro tipos de fichas. Si las fichas adyacentes de un bloque son todas del mismo tipo, entonces pueden ser eliminadas simplemente seleccionando una de ellas. El nmero de fichas en el bloque y los puntos que se obtendrn al eliminar ese bloque se muestran en la parte inferior. Cuanto ms fichas tenga un bloque ms puntos se obtendrn. Una vez que el bloque ha sido eliminado, las fichas encima de l comenzarn a caer para rellenar el espacio. Si se elimina una columna entera, entonces las fichas se desplazarn hacia la izquierda para rellenar el espacio. Dos fichas se consideran adyacentes: si estn en la misma columna y en filas consecutivas, o si estn en la misma fila y en columnas consecutivas.

Vladimir Rodrguez

158

Programacin estructurada en Pascal


En la siguiente figura se muestra paso a paso el resultado de la eliminacin de un bloque para el juego SameGame del entorno Gnome de GNU/Linux.

Se decide eliminar el bloque de fichas verdes. 1. Las fichas se desplazan hacia abajo. 2. Como quedan columnas libres a la izquierda, se desplazan todos las fichas hacia la izquierda. 3. Resultado de eliminar el bloque de fichas verdes. El juego termina cuando no hay bloques a eliminar. 3.2 Fichas Cada celda del tablero contendr una ficha del conjunto {A, B, C, D} o estar vaca. Al comenzar el juego, el tablero se llena de fichas de forma aleatoria. 3.3 Puntajes La puntuacin est basada en el nmero de fichas que se eliminen:

Nmero de fichas eliminadas Puntos obtenidos 2 3 4


Vladimir Rodrguez

0 1 4 159

Programacin estructurada en Pascal n (n - 2)^2

Si se eliminan todas las fichas hay una bonificacin de 1.000 puntos.

4. Arquitectura del sistema El sistema que implementa el juego se construir de acuerdo con la siguiente arquitectura:

usuario

^ | | v +-------+ +----------+

| motor |<-----> | interfaz | +-------+ ^ \ \ v +----------+ ^ / / /

estructura Este es un modelo simple donde tenemos dos capas o mdulos: la interfaz y el motor. La interfaz se encarga de realizar el dilogo con el usuario, capturar sus entradas e invocar las operaciones asociadas. La interfaz tambin maneja la imagen del juego en pantalla actualizndola cada vez que hay cambios. En resumen, se encarga de todo lo que tenga que ver con entrada y salida. La interfaz no realiza ninguna modificacin directa sobre la estructura de datos. El motor es el mdulo que trata con la estructura de datos que representa el juego en un estado determinado. Este mdulo estar compuesto por todos los subprogramas necesarios para ejecutar las acciones del usuario y reflejar estas en la estructura de datos. El motor no realiza ninguna operacin de entrada y salida. En esta tarea, el estudiante implementar solamente el motor. La interfaz ser provista por los docentes. En las siguientes secciones explicamos los detalles del mdulo a ser implementado.

5. Estructura La estructura de datos que representa el juego es la siguiente: 5.1 Estado del Juego El TipoEstadoJuego es un registro con los siguientes campos:

Vladimir Rodrguez

160

Programacin estructurada en Pascal


tablero: contiene el tablero del juego puntaje: contiene el puntaje actual del usuario finalizado: indica si el juego ha finalizado. TipoEstadoJuego = record tablero : TipoTablero; puntaje : Integer; finalizado : Boolean; end;

5.2 Tablero, Celdas y Fichas El tablero se representa con la siguiente estructura: TipoFicha = (A, B, C, D); TipoEstadoCelda = record case vacia : boolean of true : (); false : (ficha : TipoFicha); end; RangoFila = 1..MAX_FILAS; RangoColumna = 1..MAX_COLUMNAS; TipoTablero = record celdas : array [RangoFila, RangoColumna] of TipoEstadoCelda; topeFila : RangoFila; topeColumna : RangoColumna; end; Esta estructura es una matriz con dos topes (ver array con tope). De esta manera se pueden representar tableros de diferentes tamaos. Las celdas vlidas de la matriz son aquellas cuyas coordenadas (i,j) son tales que:

1<= i <= topeFila

1<= j <= topeColumna Las constantes MAX_FILAS y MAX_COLUMNAS se suponen definidas con valores apropiados. Estos valores estn definidos en la interfaz, de manera que el estudiante no necesita conocerlos. Cada celda del tablero puede estar vaca, o contener una ficha como indica el registro con variantesTipoEstadoCelda. Para esta implementacin las fichas son 4, y las distinguimos con las etiquetas: A, B, C o D. 5.3 Posicin y Lista de Posiciones Una posicin en el tablero se representa con la siguiente estructura: TipoPosicion = record fila : RangoFila; columna : RangoColumna end; Para representar una bloque (o conjunto de fichas) utilizaremos el tipo TipoListaPosicion, que es un arreglo con tope, como se muestra a continuacin: TipoListaPosicion = record lista : array [1..MAX_CELDAS] of TipoPosicion; tope : 0..MAX_CELDAS; end;

6. Los subprogramas

Vladimir Rodrguez

161

Programacin estructurada en Pascal


El motor del juego est constituido por un conjunto de subprogramas que trabajan sobre la estructura definida. 6.1 Procedimiento inicializarJuego Este subprograma es invocado al comienzo del juego para generar el tablero inicial. procedure inicializarJuego( cuantas_filas :RangoFila; cuantas_columnas :RangoColumna; var estado :TipoEstadoJuego); Los parmetros que recibe son:

cuantas_filas: cantidad de filas que va a tener el tablero

cuantas_columnas : cantidad de columnas que va a tener el tablero Este procedimiento debe retornar el parmetro estado configurado para iniciar el juego, esto es: para cada celda selecciona al azar una ficha: A, B, C D el juego no est finalizado el puntaje es cero 6.2 Procedimiento obtenerBloque Dado un tablero y la posicin de una celda, devuelve la lista de posiciones de celdas que estn en el mismo bloque segn las reglas del juego. procedure obtenerBloque( tablero :TipoTablero; posicion :TipoPosicion; var bloque :TipoListaPosicion) 6.3 Procedimiento obtenerBloqueMasGrande Dado un tablero, devuelve en bloque el bloque ms grande. Si hay ms de un bloque que cumpla con esta condicin, devuelve cualquiera de estos. procedure obtenerBloqueMasGrande( tablero :TipoTablero; var bloque :TipoListaPosicion); 6.4 Funcin puntosAGenerar Dado un bloque de posiciones a eliminar y un tablero, devuelve la cantidad de puntos que se generaran si se eliminara el bloque. No solo debe tomar en cuenta la cantidad de posiciones en el bloque, sino tambin debe tener en cuenta si el tablero queda vaco o no, pues puede corresponder sumar el puntaje extra. function puntosAGenerar( bloque :TipoListaPosicion; tablero: TipoTablero) : Integer; 6.5 Procedimiento ordenarBloque Este procedimiento ordena una lista de posiciones bloque de forma creciente. Esto es, una celda [i1, j1] es menor que [i2, j2] si (i1 < i2) o si (i1 = i2) y (j1 < j2). Por ejemplo, la lista ([1,1], [2,1], [3,4], [3,5], [3,6])est ordenada. procedure ordenarBloque(var bloque : TipoListaPosicion); 6.6 Procedimiento eliminarBloque Dado un bloque (o lista de posiciones de celdas a eliminar) y un estado del juego, elimina las celdas y hace los corrimientos necesarios para que el tablero del juego sea vlido nuevamente. Una vez que el bloque ha sido eliminado, las fichas ubicadas encima de l caen para rellenar el espacio. Si se elimina una columna entera, entonces las fichas se desplazan hacia la izquierda para rellenar el espacio. Se debe sumar el puntaje ganado al puntaje total del usuario. procedure eliminarBloque ( bloque :TipoListaPosicion; var estado :TipoEstadoJuego);

7. Se pide Escribir un archivo con todos los subprogramas que forman el motor del juego.

Vladimir Rodrguez

162

Programacin estructurada en Pascal


Los cabezales de los subprogramas deben coincidir exactamente con los que aparecen en esta letra. Si el estudiante realiza algn cambio se considerar que el subprograma no fue implementado. Prximamente se publicar la interfaz implementada por el equipo docente, junto con instrucciones de cmo compilar y ejecutar el programa compuesto por la interfaz y el motor. Se puede utilizar todo lo visto en las clases tericas y prcticas. Para la correccin, las tareas se compilarn con la versin 2.2.2 para windows. La compilacin y la ejecucin se realizarn en lnea de comandos. El comando de compilacin se invocar de la siguiente manera: fpc -Co -Cr -Mtp programa.pas Si trabaja con el IDE, asegrese de configurarlo para que compile de la misma manera que el comando anterior (habilitacin de Range Checking, Integer Overflow Checking y Turbo Pascal Compatible). No est permitido utilizar facilidades de Free Pascal que no forman parte del estndar y no se dan en el curso. As por ejemplo, no se pueden utilizar ninguna de las palabras siguientes: uses, crlscr, gotoxy,crt, readkey, longint, string, break, etctera. En esta tarea como en todos los problemas de este curso, se valorar adems de la lgica correcta, la utilizacin de un buen estilo de programacin de acuerdo a los criterios impartidos en el curso. De esta manera, se har nfasis en buenas prcticas de programacin que lleven a un cdigo legible, bien documentado y mantenible, tales como: indentacin adecuada utilizacin correcta y apropiada de las estructuras de control cdigo claro y legible algoritmos razonablemente eficientes utilizacin de comentarios que documenten y complementen el cdigo utilizacin de constantes simblicas nombres mnemotcnicos para variables, constantes, etctera.

8. Apndices 8.1 Nmeros aleatorios En free pascal se pueden generar nmeros al azar utilizando la funcin random. Esta funcin recibe un parmetro entero positivo y retorna un nmero aleatorio mayor o igual que 0 y menor que el parmetro recibido. El procedimiento randomize debe invocarse una sola vez, previamente a cualquier invocacin de la funcin random. El nico objetivo de esta operacin es inicializar el generador de nmeros aleatorios. A continuacin se muestra un ejemplo donde se generan 10 nmeros al azar entre 1 y 6, como si fueran lanzamientos de un dado. { inicializacin } randomize; for i:= 1 to 10 do begin { sorteo } numero:= random(6) + 1; writeln(numero); end; Tener en cuenta que la funcin random puede repetir nmeros.

Vladimir Rodrguez

163

Programacin estructurada en Pascal


8.2 Gua para resolver algunos de los problemas presentados en este obligatorio Algunos algoritmos tienen complejidades algortmicas que requieren pensarlos con cuidado. En este apndice damos algunas sugerencias para su implementacin. Obtener Bloque Un algoritmo posible consiste en manejar dos listas de posiciones: lista de pendientes y lista de visitadas, aparte del bloque (o lista) que queremos obtener como resultado. El algoritmo es el siguiente: 1. Agregar la posicin inicial a la lista de posiciones pendientes. 2. Mientras haya posiciones en la lista de pendientes, procesar cada posicin de la siguiente manera: 1. Quitarla de la lista de pendientes 2. Agregarla a la lista de visitadas 3. Agregarla a la lista de posiciones que forma el bloque que estamos buscando 4. Agregar todas las posiciones adyacentes, que sean del mismo tipo del bloque que estamos armando, y que no hayan sido visitadas, a la lista de pendientes para procesarla ms tarde. Eliminar Bloque Hay varios algoritmos que resuelven este problema. Algunos ms eficientes que otros. Una opcin es: 1. Marcar todas las celdas del bloque a eliminar como vacas, 2. Mover todas las fichas hacia abajo para cubrir los huecos que hayan quedado en las columnas. 3. Si se generaron columnas vacas, mover las columnas que contienen fichas hacia la izquierda (respetando el orden que tenan), y que las columnas vacas queden a la derecha.

9. Referencias 1. http://library.gnome.org/users/swell-foop/2.31/swell-foop.html

2.

http://en.wikipedia.org/wiki/Same_Game

Instrucciones para la interfaz grfica:


1. Introduccin Con el fin de poder probar en forma interactiva los subprogramas que se piden en la tarea 2, se les brinda el cdigo iguales.pas, al cual le faltan los subprogramas que se pide implementar. Ud. deber implementar dichos subprogramas en el archivo motor.pas. Para que esto funcione, dentro del archivo iguales.pas se encuentra la siguiente directiva: {$INCLUDE motor.pas}. Esto tiene el mismo efecto que copiar y pegar el contenido del archivo motor.pas dentro de iguales.pas en el lugar de dicha directiva. Tenga en cuenta que los subprogramas del motor.pas publicado pueden tener instrucciones a los efectos que compile iguales.pas que no necesariamente deben estar en la solucin implementada. 2. Restricciones

El programa final que implemente el juego debe funcionar sin que Ud. tenga que modificar el archivo iguales.pas. Todos los subprogramas que se pide implementar en la letra de la tarea 2, as como cualquier funcin, procedimiento, tipo, etc. extra que Ud. necesite definir, debern ser implementados en el archivo motor.pas. Las directivas, procedimientos y funciones no estndar usadas en el archivo iguales.pasfueron utilizadas con el fin de que Ud. tenga una interfaz ms amigable. Sin embargo, como es regla en este curso, Ud. no puede utilizar facilidades de Free Pascal que no forman parte del estndar y que no se dan en el curso para implementar los subprogramas que se piden o cualquier otro subprograma extra que necesite.

Vladimir Rodrguez

164

Programacin estructurada en Pascal


Ud. no debe usar variable globales, toda la comunicacin con la interfaz debe ser a travs de los parmetros de los subprogramas. 3. Descripcin de la interfaz 3.1 Pantalla principal La interfaz se muestra en la siguiente figura:

Bsicamente tiene un cabezal, un tablero y una barra de estado:

En el cabezal est el nombre del juego y se despliegan mensajes cuando el jugador ha ganado o perdido. En el tablero se ven: las celdas vacas (que se representan con el caracter .) o con fichas (que se representan con los caracteres A, B, C o D con un color distinto cada uno). la posicin en donde est parado el usuario (que se indica con el cursor que est parpadeando). el bloque de fichas adyacentes del mismo tipo que la ficha de la posicin en donde est parado el cursor (que se resaltan con un color ms brillante) En la barra de estado se puede ver: la fila y la columna donde est posicionado el usuario, la cantidad de fichas del bloque de fichas adyacentes del mismo tipo que la ficha de la posicin en donde est parado el usuario. los puntos a generar por el usuario, si borra el bloque de fichas adyacentes del mismo tipo que la ficha de la posicin en donde est parado los puntos ya generados en jugadas (o acciones) previas.

Usando las flechas del teclado y algunas teclas se consigue probar y jugar. 3.2 Pantalla inicial Cuando se inicia el juego aparece la siguiente pantalla, que nos permite elegir el tamao del tablero o cargar el estado del juego (nuevo o ya empezado) desde un archivo.

Vladimir Rodrguez

165

Programacin estructurada en Pascal

3.3 Ayuda Por ms informacin Ud. puede ver la ayuda que trae la interfaz. Presionando la tecla h (de help en ingls) se obtiene la siguiente pantalla:

4. Comunicacin interfaz-motor 4.1 Invocacin a inicializar Juego(...): Cuando se inicia un juego nuevo seleccionando el nivel (fcil, intermedio, difcil), la interfaz invoca al procedimiento inicializarJuego() pasando como parmetros cierta cantidad de filas y columnas dependiendo de cada nivel. 4.2 Invocacin a los otros subprogramas del motor Cuando el usuario se posiciona sobre una celda determinada y presiona algunas de las teclas correspondientes a eliminar bloque, eliminar bloque ms grande, etc., la interfaz invoca los procedimientos y funciones que correspondan pasando los parmetros que se necesiten, el estado del juego y/o la posicin, dependiendo del procedimiento o funcin del motor que est invocando.

Vladimir Rodrguez

166

Programacin estructurada en Pascal


Por lo tanto, la comunicacin entre la interfaz y el motor se realiza usando solo los parmetros de los procedimientos y las funciones definidos en el motor.pas. 5. Funcionalidades Aparte de poder jugar en forma interactiva, esta interfaz ofrece otras funcionalidades que le permitirn encontrar y corregir errores ms fcilmente, por ejemplo:

Listar las posiciones del bloque de fichas seleccionado que devuelve el procedimientoobtenerBloque()

Listar las posiciones del bloque de fichas seleccionado que devuelve el procedimientoobtenerBloque(), ordenadas tal cual las ordena el procedimiento ordenarBloque() Volver atrs (o deshacer) una accin. Guardar la configuracin actual del estado del juego en un archivo de texto. Cargar la configuracin de un estado del juego desde un archivo de texto. Guardar en un archivo de texto el historial de los sucesivos estados del juego y las acciones que se realizaron. 6. Recomendaciones 6.1 Para compilar Cree una carpeta (o directorio) donde va a trabajar, descargue los archivos iguales.pas (que contiene la interfaz) y motor.pas (que solo contiene los encabezados de los subprogramas) y cpielos a dicha carpeta. Compile el archivo iguales.pas desde la lnea de comandos con: fpc -Co -Cr -Mtp iguales.pas, o desde el IDE teniendo abierta la ventana con el archivo iguales.pas. El compilador se da cuenta automticamente de que tiene que incluir el cdigo del archivo motor.pas donde est la directiva mencionada antes. Esto ya va a generar una interfaz sencilla que, si bien no permite crear juegos nuevos ni realizar acciones, s permite cargar archivos con juegos de prueba, como se explica a continuacin. A medida que implemente los procedimientos y funciones, podr realizar ms acciones del juego. 6.2 Para probar usando la interfaz Hasta que usted no implemente el procedimiento inicializarJuego(), no va a poder generar sus propios tableros. Pero s puede ir probando los otros procedimientos y funciones, por ejemplo cargar el juego desde uno de los archivo de ejemplo que le proporcionamos. A continuacin se proporcionan algunos archivos generados desde la interfaz, los cuales se pueden cargar sin necesidad de implementar los procedimientos y funciones del motor.

estadoJuego1.txt estadoJuego2.txt estadoJuego3.txt estadoJuego3-empezado.txt

A continuacin se proporcionan algunos archivos con historiales de ejemplo. Los historiales contienen la secuencia de juegos que se generan a partir de un estado inicial y la aplicacin sucesiva de acciones eliminarBloque o eliminarBloqueMasGrande:

historial1.txt historial2.txt historial3.txt

Adems Ud. puede probar los procedimientos y funciones implementando su propia interfaz y/o pequeos programas para probar cada procedimiento por separado. Recuerde que lo que Ud. debe implementar son los procedimientos, la interfaz es simplemente una ayuda para probar y jugar con su implementacin del motor.pas.

Vladimir Rodrguez

167

Programacin estructurada en Pascal


Descarga del programa de prueba: Les dejo aqu el programa ya creado para que puedan probar como funciona, as ya saben como debe de quedarles. Hagan click aqu para bajar el archivo.

GUA PARA REALIZAR TEST DE ESTE PROGRAMA: 1. Introduccin


Como parte de un proceso industrial, la fase de pruebas aade valor al producto generado. Todos los programas tienen defectos (somos humanos) y la fase de pruebas ayuda a descubrirlos. Ese es uno de los principales valores que aade. Probar un programa es ejecutarlo con la peor intencin con el fin de encontrarle defectos. Para sto se disean casos de prueba. Un caso de prueba consta de: entradas (parmetros de entrada al programa) resultados esperados

En esta hoja encontrarn casos de prueba de ejemplo (casos de prueba bsicos) y puntos que deberan tener en cuenta a la hora de probar. As que a hincarle los dientes a esto que ser de gran ayuda para ustedes!! 2. Cmo arman un puzzle? En general, uno empieza por el borde, luego arma las partes ms fciles, las difciles, y siempre, para cada parte, uno se va cerciorando que se est uniendo las piezas correctamente. Luego juntamos las partes prearmadas hasta llegar a la figura final. 3. Por qu estamos viendo cmo armar un puzzle? La idea de cmo armar un puzzle e implementar y probar el juego iguales tiene muchas similitudes. El borde y algunas partes ya estn prearmados y testeados (iguales.pas) y le pedimos que armen y testeen las partes faltantes (motor.pas) para completar el juego o puzzle. Parece una tarea fcil, no? Por lo tanto para probar su tarea deben tener en cuenta 3 puntos de prueba y en este orden: 1. Probar cada una de las partes armadas por ustedes por separado. O sea, cada subprograma o procedimiento por separado. 2. Probar que las partes encajan correctamente en lo que ya est armado. O sea, que al unir los subprogramas implementados por ustedes con los implementados por nosotros no generen errores. 3. Probar finalmente que todas las partes junto con el borde funcionan correctamente. O sea, nuestro puzzle es el que est en la imagen de la caja. Esto se hace probando desde la interfaz. Ac es dnde se pone ms divertido, es hora de jugar. Como bien dice la letra de la tarea Ud. puede probar los procedimientos implementando su propia interfaz, y/o pequeos programas para probar cada procedimiento por separado. Recuerde que lo que Ud. debe realizar son los procedimientos, la interfaz es simplemente una ayuda para probar y jugar con su motor. 4. Indicaciones y pautas a seguir para las pruebas 4.1 Probar por separado los subprogramas Prueben todos los procedimientos por separado. Esta tcnica les ser de gran ayuda al momento de hacer la prueba desde la interfaz. Es decir, disminuir significativamente la cantidad de errores que encontrarn y su gravedad. Pueden armarse un programa principal auxiliar que simplemente

Vladimir Rodrguez

168

Programacin estructurada en Pascal


haga la llamada al procedimiento bajo prueba y luego imprima el resultado en pantalla para que puedan verificar la correctitud de su resultado. A modo de ejemplo se presentan los siguientes programas:

PruebaInicializarJuego.pas PruebaObtenerBloque.pas

que sirven para probar en forma independiente los procedimientos incializarJuego y obtenerBloque. Recomendamos que armen programas similares para probar el resto de los subprogramas por separado. 4.2 Pautas para los casos de prueba Recomendamos que piensen los casos de pruebas antes de empezar a probar y que anoten sus ideas. Recuerden que un caso de prueba se puede decir que est formado por entradas (en este caso, parmetros del procedimiento), un resultado esperado y un resultado obtenido. Adems se puede agregar una descripcin para entender rpidamente qu se est atacando. La idea es que prueben lo que se les sugiere abajo. Si tienen algunas ideas ms, no las descarten, senlas para probar, incluso en combinacin con estas. inicializarJuego Diferentes dimensiones de tableros, chicos, medianos, grandes Casos lmites en las dimensiones: mximo tablero (MAX_FILAS * MAX_COLUMNAS), mnimo tablero (1 x 1) Verificar que el juego no est finalizado Verificar que el puntaje es cero Verificar que las fichas se distribuyen aleatoriamente sobre el tablero

obtenerBloque Diferentes ubicaciones de la posicin: en el centro del tablero, en el borde derecho, en el borde izquierdo, en el borde superior, en el borde inferior Diferentes fichas en la celda de la posicin: con ficha A, B, C, D, vaca Diferentes adyacentes a la celda de la posicin: con adyacentes a la derecha, a la izquierda, arriba, y abajo Sin adyacentes

obtenerBloqueMasGrande Diferentes estados, situaciones, posiciones (como en el caso anterior) Probar con un tablero con solo bloques unitarios Probar con un tablero lleno de fichas del mismo color (el bloque es todo el tablero) Probar con un tablero con bloques del mismo tamao

puntosAGenerar Siendo n la cantidad de fichas en el bloque: Probar cuando el resultado es 0 puntos (n=0, n=1, o n=2) Probar para n>2 Probar para un n grande

ordenarBloque Ordenar Ordenar Ordenar Ordenar un bloque un bloque un bloque un bloque de tamao>1 de tamao 1 de tamao cero que abarque todo el tablero

eliminarBloque Eliminar un bloque del centro del tablero

Vladimir Rodrguez

169

Programacin estructurada en Pascal


Eliminar un bloque que provoque uno o varios desplazamientos de columnas. Eliminar un bloque de tamao 1 (esto no debera tener efecto) Eliminar un bloque que abarque todo el tablero

4.3 Integrar el motor.pas con iguales.pas Adems de manejar bien las estructuras ya definidas, deben estar seguros que los datos que les llegan son los esperados por ustedes y los datos que devuelven son los esperados por la interfaz. En otras palabras deben verificar que estn tomando correctamente los datos que les pasan por parmetro y devolvindolos correctamente tambin. 4.4 En el juego, desde la interfaz Esta es la ltima. Si hicieron bien las pruebas anteriores no deberan tener muchos errores en esta etapa. Les sugerimos que para esta parte lo que ms deben hacer es jugar. Recuerden que la intencin debe ser encontrar fallas y no salterselas. Lo mejor es enfocarse en buscar cierto tipo de errores durante varias partidas seguidas. Piensen que tienen una misin, encontrar defectos, entonces por varias partidas ponen el foco en buscar ciertos defectos, por ejemplo, eliminar bloques y verificar que las dems fichas se desplazan correctamente. Es importante que se guarden los historiales de cada partida(*), as cuando ocurre una falla, pueden reproducirla. Esto les servir al momento de verificar que hayan arreglado el defecto. Les podr ser til anotar en una planilla la correspondencia entre los errores y los archivos de historial. En las misiones, pueden intercalar los distintos niveles de tablero de la interfaz, o alguno armado por ustedes. (*) Recuerde que la interfaz proporcionada por los docentes, le permite guardar y cargar desde un archivo de texto el estado de un juego (recin iniciado, o ya comenzado). Tambin se puede guardar en un archivo de texto el historial de los estados por los que pas el juego y las acciones que se realizaron. 5. Indicaciones tiles Cuando utilicen casos de prueba Ejecuten todos los casos de prueba y anoten sus resultados antes de comenzar la revisin de los que fallaron. Esto les facilitar el trabajo. A la hora de empezar la revisin de los casos que fallaron. Se puede seguir estos pasos: Revisar la formulacin del caso de prueba. Puede que est mal el caso y no sea el programa. Si el caso de prueba es correcto, se pasa a detectar qu parte del cdigo est generando la falla. Esto lo pueden hacer debugueando por ejemplo. Cuando hayan arreglado todos los errores, ejecuten los casos de prueba que en un principio no fallaron. Esto es para asegurarse que los cambios hechos no introdujeron errores en lo que andaba bien.

Algunas indicaciones ms para cuando prueben desde la interfaz: Al igual que con los casos de prueba, ejecuten varias misiones, las que ustedes crean convenientes, antes de empezar a corregir los errores. 6. Conceptos de testing manejados en esta gua Testing Unitario (probar cada parte por separado) Testing de Integracin (probar cmo encajan las partes entre s) Testing de Sistema o Caja Negra (probar que el puzzle armado es igual al de la imagen en la caja)

Vladimir Rodrguez

170

Programacin estructurada en Pascal

Despedida y Agradecimientos:
Hasta aqu hemos llegado con este manual, de verdad espero que les haya servido para algo as como esperar sus correos para preguntar, corregir, sugerir y dems. La creacin de este documento est inspirada en el agradecimiento a todos aquellos que al igual que yo han decidido utilizar su tiempo para ayudar a quienes buscan informacin en la web, una ayuda sin fines de lucro sino ms bien todo lo contrario, una ayuda sin la cual yo hoy no sabra nada. Muchas gracias a todos ellos, muchas gracias a quienes publiquen y difundan este manual, a todas aquellas pginas web que permitan su descarga gratuita, a todos quienes se tomen enserio este curso y aprendan realmente. No es una despedida para siempre porque continuar con ms manuales, manuales para los cuales asumir que ya han ledo este. En la segunda entrega, como ya dije, abordaremos el lenguaje MODULA-2 el cual sigue siendo PASCAL pero orientado a la modularizacin. Con dicho lenguaje aprenderemos a crear programas separados por mdulos individuales, lo cual nos da infinitas posibilidades; abordaremos la recursin como herramienta y sin la cual no podrn solucionar muchos problemas, adems de que les proveer del poder de realizar taras que de otro modo seran imposibles; abordaremos estructuras como las de rboles, colas y otras tantas usadas en muchos tipos de programas; aprendern acerca del diseo de TAD (Tipos Abstractos de Datos) entre muchas otras cosas. Los programas seguirn siendo vistosamente horribles pero potencialmente competentes, lo cual es lo ms importante, porque de nada sirve saber crear hermosas interfaces grficas si nuestros programas no saben trabajar. Estoy pensando tambin crear un anexo a este manual, no para aprender conceptos nuevos, sino para traducir estos conceptos a un lenguaje moderno como Java, a modo de incentivo. El aprendizaje seguir orientado a la segunda entrega de este tutorial, por lo cual lo otro es un simple agregado a este, pero an lo estoy pensando ya que Java obliga a aprender conceptos de la programacin orientada a objetos y an no hemos trabajado con ello en absoluto. Habiendo ledo todo este manual cualquiera de ustedes debera poder iniciarse en otro lenguaje si leen manuales de l, podrn al menos hacer casi las mismas cosas que hasta ahora pero tal vez con un modo de trabajo mucho mejor y un tanto ms sencillo. Sin embargo esperar que lean la prxima entrega, la cual espero est lista para mediados de este ao, o sea, Junio o Julio de 2011. Gracias nuevamente a todos los que me han ledo, a todos los que me escribirn y a todos quienes decidan aportar algo ms a esto. Estar a su disposicin siempre que necesiten ayuda y tambin para recibirla ya que yo tambin estoy aprendiendo, recin ingresando a este mundo tan complejo y tan interesante. Gracias a todos y a todas. Un cordial saludo de su amigo Vladimir Rodrguez. Ha sido un gusto escribir esto y, aunque me ha llevado su tiempo, hoy me siento feliz de poder mostrarlo. Gracias.

Vladimir Rodrguez

171

Programacin estructurada en Pascal

Vladimir Rodrguez

172

Programacin estructurada en Pascal NDICE DE CONTENIDO


PRIMERA PARTE Conceptos bsicos de programacin Introduccin Nociones sobre Lenguaje de Programacin Instalando el ambiente de desarrollo Free-Pascal Verificando Instalacin Corrigiendo Bug y configurando para comenzar Configuracin Range Checking e Integer Overflow NUESTRO PRIMER PROGRAMA: HOLA MUNDO!!! Write y Writeln Introduccin a las variables Ejemplo de asignacin Leer ms de una variable a la vez Ejercicio Introduccin a la compatibilidad de tipos Errores en tiempo de Ejecucin y errores en tiempo de Compilacin Palabras reservadas Identificadores Tipos de datos Operadores en pascal Precedencia de operadores Funciones matemticas de pascal Un ejemplo del uso de DIV y MOD. Introduccin a los comentarios Introduccin a las constantes Booleanos Algunas notas Ejercicios SEGUNDA PARTE Seleccin y Repeticin Introduccin Seleccin. Instruccin IF...THEN e IF...THEN...ELSE Anidacin de la instruccin If...then Anidacin de un if...then con un if...then...else Condiciones compuestas Tablas de verdad Operadores relacionales Un ejemplo matemtico Instruccin de seleccin CASE...ELSE Ejercicio Secuencia de repeticin FOR Anidacin de FOR Ejercicios DEBUGER Secuencia de repeticin WHILE...DO Un pequeo juego Generar nmeros aleatorios Secuencia de repeticin REPEAT...UNTIL Centinela Ejercicio Un ejemplo ms complejo. Contador de palabras Ejemplo de captura de error Tabla Ascii Ejercicios

4 5 6 8 9 10 11 13 14 15 15 16 17 18 19 20 20 20 21 21 22 23 26 26 26

28 29 30 30 32 32 33 33 36 38 39 40 41 43 44 46 47 48 48 49 49 49 50 51

Vladimir Rodrguez

173

Programacin estructurada en Pascal


TERCERA PARTE Introduccin a los TIPOS definidos por el programador Subrangos y Arreglos Introduccin Subrangos Arreglos Declaracin Utilizacin de arreglos Hacer WRITE y READ de un arreglo Ejercicios Declaracin annima de una arreglo Recorriendo arreglos Bsqueda de un elemento Ejercicios Arreglos multidimensionales Arreglos bidimensionales Ejercicios Arreglos tridimensionales REALIZANDO UN PROYECTO: MASTER MIND CUARTA PARTE SUBPROGRAMAS: Procedimientos y Funciones Introduccin Procedimientos Declaracin y llamado Variables Globales y Locales. Introduccin al Alcance de Identificadores Sombreado de Identificadores Parmetros: Pasaje por Valor Declaracin de parmetros de tipos diferentes Asignaciones de parmetros Parmetros Nominales y parmetros Efectivos Funciones Declaracin y llamado Funciones Booleanas Llamar a un subprograma desde otro subprograma Parmetros: Pasaje por Referencia Ejercicios QUINTA PARTE Enumerados Registros con y sin variante Arreglo con tope Introduccin Enumerados Read y Write con enumerados Comparaciones con enumerados Ejercicios Registros Declaracin Una estructura compleja Ejercicios BASE DE PRODUCTOS-Parte 1 Limpiar la pantalla La funcin WITH...DO Ambigedad con WITH...DO Registro con variante Arreglo con tope Ejercicios BASE DE PRODUCTOS-Parte 2

54 55 56 56 57 59 59 60 60 62 63 65 65 66 67 68

72 73 73 76 79 80 82 83 83 84 84 85 87 88 93

100 101 102 102 105 107 107 109 109 110 117 118 119 120 123 124 130

Vladimir Rodrguez

174

Programacin estructurada en Pascal


SEXTA PARTE Memoria Dinmica: El tipo Puntero Listas Encadenadas Simples Introduccin El tipo Puntero Declaracin El procedimiento NEW y el operador ^ El procedimiento DISPOSE El puntero nulo, la constante NIL Ejercicios Listas encadenadas simples Lista vaca Fin de lista Largo de una lista Bsqueda de un elemento Agregar un elemento al principio Agregar elemento al final Borrar el primer elemento de una lista no vaca Borrar una lista completa Ejercicios BASE DE PRODUCTOS-Parte 3 UN LTIMO PROYECTO Letra Instrucciones para la interfaz grfica Descarga del programa de prueba Gua para realizar el test de este programa DESPEDIDA Y AGRADECIMIENTOS

138 139 139 139 142 144 145 148 151 151 153 153 153 154 154 154 155 156

157 164 168 168 171

Vladimir Rodrguez

175

Programacin estructurada en Pascal

Vladimir Rodrguez

176

También podría gustarte