0% encontró este documento útil (0 votos)
129 vistas136 páginas

Historia y Conceptos de Programación

Los lenguajes de programación evolucionaron de lenguajes máquina a lenguajes de alto nivel para facilitar la programación. Los primeros lenguajes como FORTRAN y COBOL aparecieron en los años 50 y 60 para dominios específicos. En los años 70, lenguajes como Pascal y C introdujeron paradigmas estructurados y modulares que siguen usándose hoy. Más recientemente, paradigmas como la programación orientada a objetos han cambiado la concepción de aplicaciones.

Cargado por

Jon Tze Lou
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
129 vistas136 páginas

Historia y Conceptos de Programación

Los lenguajes de programación evolucionaron de lenguajes máquina a lenguajes de alto nivel para facilitar la programación. Los primeros lenguajes como FORTRAN y COBOL aparecieron en los años 50 y 60 para dominios específicos. En los años 70, lenguajes como Pascal y C introdujeron paradigmas estructurados y modulares que siguen usándose hoy. Más recientemente, paradigmas como la programación orientada a objetos han cambiado la concepción de aplicaciones.

Cargado por

Jon Tze Lou
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

Introducción e Historia

La finalidad de un lenguaje de programación es "decirle" al ordenador qué es lo que


tiene que hacer paso a paso. Esta definición da que pensar: no parecen muy listos los
ordenadores. Debido a esto es muy frecuente la expresión

Los ordenadores son tontos.

Necesitan de alguien que les indique lo que tienen que hacer. Y ese "alguien" es el
programador. Pero una vez que saben qué hacer y cómo, lo pueden repetir siempre que
deseen, sin error posible y a velocidades muy superiores a las que podría hacerlo una
persona.

Desgraciadamente, el ordenador y las personas hablan idiomas diferentes: el ordenador


entiende unas determinadas secuencias de ceros y unos, llamado lenguaje o código
máquina. Este lenguaje o código máquina es difícil de aprender, difícil de utilizar e
incluso aún más difícil de modificar. Además ese código máquina no es el mismo para
todos los ordenadores lo que se traduce en que los programas realizados para un tipo de
máquina no sirven para el resto. Así es difícil para el programador indicarle al
procesador las instrucciones directamente en lenguaje o código máquina.

Se pensó que sería más sencillo trabajar en un lenguaje parecido o similar al lenguaje
humano (o natural). Una vez expresado el conjunto de instrucciones en ese lenguaje
cercano al lenguaje natural, será necesario traducir ese lenguaje a código máquina. Pero
esta labor se puede programar y que sea el ordenador el que automáticamente haga la
traducción a lenguaje máquina. De esta forma surgieron los lenguajes llamados de alto
nivel y los programas encargados de la conversión de un lenguaje a otro: los
traductores. Estos últimos se enmarcan hoy en día en los denominados procesadores del
lenguaje que no se limitan exclusivamente al tratamiento de lenguajes de programación
sino que extienden su campo de aplicación mucho más lejos. El objetivo, sin duda, es
que en algún momento los ordenadores sean capaces de entender el lenguaje que
emplean las personas. Actualmente esta meta aún se encuentra lejos pero se está
trabajando en esta línea desde hace ya varios años y los resultados son prometedores.

Algoritmo

Se define "algoritmo" como el conjunto de pasos necesarios para resolver un problema.


El algoritmo es por tanto la "receta" que señala qué se debe hacer en cada momento y
bajo qué condiciones hacerlo. El algoritmo se puede expresar de múltiples formas
aunque actualmente la más utilizada combina diferentes tipos de diagramas junto con
especificaciones muy próximas al lenguaje natural (pseudocódigo). El conjunto de
pasos para resolver un problema puede tener diferentes niveles de abstracción dando
lugar a diferentes niveles de concrección del algoritmo. El procedimiento natural parte
de una especificación muy general y la refina cíclicamente hasta alcanzar el grado de
detalle necesario. ¿Cuál es dicho grado de detalle?. Pues aquel que permita interpretar el
algoritmo sin ambigüedades. Como es lógico el contexto condiciona el grado de detalle
necesario. Haciendo un pequeño símil con el mundo de la cocina, el algoritmo
representa la receta y por lo tanto no es lo mismo una receta diseñada para ser
interpretada por un experto cocinero que una diseñada para una persona que nunca ha
cocinado.
Programa

Podemos definir un programa como un conjunto ordenado de instrucciones expresadas


en un lenguaje de programación que implementan un algoritmo.

Un lenguaje de programación, al igual que un lenguaje natural, estaría constituido por:

• Un conjunto de símbolos: letras, símbolos de puntuación, etc. Léxico del


lenguaje.
• Una serie de normas para la correcta combinación del anterior conjunto.
Gramática y semántica del lenguaje.

Combinando correctamente los símbolos será capaz de crear programas. Los programas
serán más sencillos de escribir cuanto más cercano sea el lenguaje de programación al
lenguaje humano. En realidad son muy parecidos al lenguaje dominante en el mundo de
la informática: el inglés. Pero no se asuste, esto no es un curso de idiomas.

Evolución Histórica

Se ha comentado previamente que el primer lenguaje de programación fue el lenguaje


máquina. A continuación aparece el Lenguaje Ensamblador (Assembly) en un intento de
sustituir indescifrables secuencias de ceros y unos por símbolos y códigos nemotécnicos
(códigos cuyos nombres recuerdan la acción que representan) para especificar
instrucciones del código máquina. Cada instrucción del código máquina se corresponde
con una instrucción en lenguaje ensamblador. Fue un primer avance para simplificar las
tareas de programación.

En los años 50 comienzan a aparecer lenguajes de carácter más humano. En 1956


aparece el lenguaje FORTRAN (FORmula TRANslation) de la mano de IBM. Este
lenguaje conserva algunos vínculos con la máquina. Es un lenguaje que aún se usa en
entornos muy específicos. En 1958 aparece el lenguaje ALGOL (ALGOritmic
Language). En 1959 se crea el LISP en el MIT (Instituto Tecnológico de
Massachusetts), lenguaje orientado al área de la Inteligencia Artificial.

En 1960 el DoD (Departamento de Defensa de [Link].) crea el COBOL (Common


Business Oriented Language), lenguaje orientado a la gestión que ha sido durante
muchos años muy utilizado en banca y empresas en general. En la década de los 60 en
la Universidad de Darmouth se desarrolla el BASIC (Beginners All-Purpose Symbolic
Instruction Code). Este lenguaje no está pensado para un dominio de aplicación
concreto, como COBOL o LISP, sino que las aplicaciones pueden ser de muy diverso
tipo, como se verá más adelante en el curso esto es lo que se denomina un lenguaje de
propósito general, en el caso de BASIC muy vinculado a los procesos de iniciación.

En 1971 N. Wirth crea PASCAL. Una de las principales características de este lenguaje
es que es fuertemente estructurado. Será el que nos acompañe a lo largo de este curso.
En la década de los 70 Dennis Ritchie crea el Lenguaje C. C es un lenguaje que ha
presentado una evolución pareja a la del sistema operativo UNIX. Hoy en día el
lenguaje C sigue siendo muy utilizado. La ventaja es que salvando las distancias tienen
muchas analogías con PASCAL, lo que permite que una persona que conozca PASCAL
pueda aprender C en muy poco tiempo.
A partir de ese momento la aparición de nuevos lenguajes y revisiones de los anteriores
ha sido constante, sin mencionar numerosos lenguajes de programación desarrollados
específicamente para tareas muy concretas. También han surgido todo tipo de variantes
de los lenguajes anteriores con características de tipo visual o añadiendo otros
paradigmas de programación como son la programación orientada a objetos, la
programación basada en eventos, la computación orientada a servicios y muchas otras.
Como posibles ejemplos tenemos Visual C, Visual Basic, C++, Pascal Orientado a
Objetos, Java, SQL, PHP y un largo etcetera. En la dirección
[Link] hay un cuadro muy interesante que muestra la cronología
de 50 lenguajes de programación con enlaces a la descripción de cada uno. Un cuadro
mucho más completo que alcanza más de 2500 lenguajes se puede ver en
[Link]

Con el desarrollo de las "interfaces" gráficas las aplicaciones actuales se manejan "a
golpe de ratón" por lo que se han desarrollado herramientas visuales que permiten
crear aplicaciones apoyándose en rutinas ya realizadas para el manejo de ventanas,
menús desplegables, botones, etc. En el momento que se tienen claros los conceptos de
programación básicos, el salto a este tipo de programación es muy sencillo.

Con el paso del tiempo los modelos de programación, más conocidos como "paradigmas
de programación", han ido evolucionando y han surgido nuevos enfoques. Inicialmente
la programación en código máquina y la programación en lenguaje ensamblador estaban
fundamentadas en instrucciones que hacían operaciones y en instrucciones que alteraban
la ejecución secuencial de las mismas a través de saltos incondicionales. La propuesta
de Wirth a través del lenguaje Pascal asentó dos paradigmas:

• El paradigma modular, en el que un programa se divide en módulos


(subprogramas o subrutinas) con el fin de hacerlo más legible, manejable y
reutilizable.
• El paradigma estructurado, en el que se utilizan únicamente tres
estructuras de control (secuencia, selección e iteración o bucles),
considerando contraproducente el uso de instrucciones de salto o
transferencia incondicional.

Ambos paradigmas serán estudiados en detalle a lo largo de este curso y la práctica


totalidad (con algunas excepciones muy específicas) de los lenguajes de programación
utilizan ambos paradigmas como base, aunque luego adopten otros que coexisten con
los primeros. En los años 80, el paradigma de la orientación a objetos modificó la
concepción de aplicaciones. Conceptualmente su diseño es más complejo pero facilita la
reutilización de los programas y en cierta forma refleja de modo más natural la realidad
que se pretende modelar a la hora de desarrollar una aplicación. De todas formas, los
conceptos de la programación estructurada y modular siguen siendo útiles en la
programación orientada a objetos y en otros paradigmas que se han ido afianzando con
el tiempo como son la programación basada en eventos, la programación orientada a
servicios, la programación basada en aspectos, etc.

En general todos los lenguajes de alto nivel tienen propiedades comunes: el uso de
sentencias simples, la existencia de variables, expresiones, estructuras de control y
subprogramas. Todos estos conceptos y su utilización serán objeto de los temas
siguientes.
El lenguaje Pascal es uno de los más adecuados para aprender y consolidar dichos
conceptos.
Clasificación

Clasificar nunca es fácil puesto que requiere establecer a priori unos criteros concretos
que permitan dividir en clases o tipos el conjunto de elementos a clasificar. Dado que es
muy frecuente que estos elementos tengan aspectos comunes, otros con ciertos matices
y otros claramente diferentes, la clasificación siempre puede no ser tan rigurosa como
cabe pensar. Vamos a realizar varias clasificaciones de los lenguajes de programación
en función de diferentes criterios:

1. Según su proximidad al lenguaje máquina:


o Lenguajes de bajo nivel: Son distintos para cada procesador, es decir que
cada tipo de ordenador posee el suyo. Controlan directamente los
recursos hardware de la máquina. Como ejemplos tenemos el lenguaje
máquina o el lenguaje ensamblador (Assembly).
o Lenguajes de medio nivel: Tal y como refleja su nombre este grupo
alberga aquellos lenguajes que tienen algunas características de los de
bajo nivel y otras de los de alto nivel. El ejemplo más representativo es el
lenguaje C.
o Lenguajes de alto nivel: como Pascal, PHP, Java, etc… Son
independientes del procesador. Son más sencillos y legibles pero generan
un código mucho menos eficiente (velocidad y tamaño) que los de bajo
nivel. Para poder ser ejecutados necesitan un procesador que bien trata
una vez el código y genera un programa ejecutable por un procesador
(compiladores) o bien lo interpretan línea por línea cada vez que son
ejecutados (intérpretes).
2. Según el propósito del lenguaje: cuando hablamos de propósito específico o
general nos referimos al dominio de las aplicaciones que se pueden desarrollar
con ese lenguaje.
o Lenguajes de propósito general: está pensado para desarrollar
aplicaciones de cualquier dominio de aplicación, desde juegos a cálculos
matemáticos. Son ejemplos de este tipo Pascal, C o Java.
o Lenguajes de propósito específico: está pensado para desarrollar
aplicaciones de un dominio concreto. Por ejemplo Matlab orientado al
desarrollo de aplicaciones matemáticas (que realicen cálculos más o
menos complejos) o LISP orientado a aplicaciones con aplicación en el
campo de la inteligencia artificial.

Por tanto, cuando hablamos de propósito específico o general nos referimos al


dominio de las aplicaciones que se pueden desarrollar con ese lenguaje, es decir,
un lenguaje de propósito general está pensado para aplicaciones de cualquier
dominio mientras que uno de propósito específico está pensado para
aplicaciones de un dominio concreto. Un posible ejemplo de lenguaje específico
es Matlab, un lenguaje de programación pensado para realizar aplicaciones que
hagan cálculos matemáticos (más o menos complejos). Lenguajes como C o
Pascal son de propósito general, es decir los programas desarrollados pertenecen
a cualquier dominio de aplicación (desde juegos a cálculos matemáticos…).

3. Según su orientación:
o Lenguajes orientados al procedimiento: son lenguajes imperativos como
Pascal en los que se describen los pasos que han de darse para resolver
un determinado problema. Se explica como resolver un problema.
o Lenguajes orientados al problema: como por ejemplo Prolog. En estos
lenguajes lo que se describe es el problema en sí; son de tipo declarativo.
o Lenguajes orientados a objeto: son lenguajes en los que se modela la
realidad centrándose en los elementos que la componen.

En este curso se estudiará un lenguaje de alto nivel, de propósito general y orientado al


procedimiento o imperativo: el lenguaje Pascal.

Lenguajes de Alto Nivel

Los lenguajes de alto nivel buscan:

• Sencillez: ser un medio sencillo para expresar la solución de problemas.


• Simplicidad: contar con un conjunto reducido de operaciones básicas y un
conjunto de reglas para combinar las anteriores.
• Eficiencia: de manera que permitan una traducción rápida y un código máquina
lo más eficiente posible.
• Legibilidad: facilitando la comprensión del código y presentando la posibilidad
de añadir comentarios que aunque no aportan nada al propio programa, permite
que otros programadores o incluso el mismo autor transcurrido el tiempo puedan
comprender su contenido con facilidad. Todo esto hace que sea más sencillo
depurar o modificar el código incluso por personas que no lo han realizado.
• Portabilidad: los lenguajes de alto nivel son independientes de la máquina para
la que se esté haciendo un determinado desarrollo. Esto permite que el esfuerzo
de programación no esté condicionado por la variedad de plataformas en las que
se desea ejecutar.

Características de los lenguajes de alto nivel

Las características más importantes que deben presentar este tipo de lenguajes son las
siguientes:

• Utilizar un juego de caracteres determinado (por ejemplo, no admiten la "ñ") y


un juego de palabras reservadas que constituyen el léxico del lenguaje..
• Presentar unas reglas sintácticas de manera que la estructura de los programas
debe ceñirse a las mismas. Estas reglas conforman la gramática del lenguaje.
• Tener capacidad para la realización de operaciones de tipo aritmético,
relacionales y lógicas incluyendo el tratamiento de cadenas de texto.
• Tener capacidad para bifurcar o repetir el código (o partes de él) en lugar de
ejecutarlo siempre secuencialmente.
• Tener facilidades para la programación modular basada en subprogramas.

Veamos a continuación que elementos son necesarios para la realización de un


programa.
Entornos de programación

Un entorno de programación es un programa o conjunto de programas que asisten al


programador en la ejecución de todas las tareas necesarias para el desarrollo de un
programa o aplicación. Estas tareas son básicamente las siguientes:

• Edición del programa.


• Compilación y enlazado.
• Ejecución.
• Depuración.

Hay quien además incluye la creación de documentación complementaria que facilita el


mantenimiento del programa dentro de estas funciones.

Este tipo de entornos incorporan numerosas herramientas, utilidades, aplicaciones ya


desarrolladas, ejemplos, tutoriales, etc. Todas ellas encaminadas a facilitar y mejorar el
desarrollo.

Editores

El primer elemento necesario para el desarrollo de un programa es un editor de texto.


Un editor es un programa que nos permite escribir (editar) las instrucciones del
programa y posteriormente guardar el programa en un fichero. Cualquier editor de texto
se puede utilizar para editar programas con la única precaución de que a la hora de
guardar, salvar o almacenar el programa sólo se almacene el texto sin opciones de
formato: negrita, estilos, itálica, etc.

Lo normal es utilizar un editor especialmente preparado para la programación. Estos


tienen facilidades para la corrección de errores, destacan las palabras del lenguaje en
colores, y en general facilitan la labor del programador.

Procesadores del lenguaje: traductores, compiladores e intérpretes

Una vez editado nuestro programa es necesario que este sea procesado y tranformado en
ódenes que puedan ser ejecutadas por el ordenador. Estas órdenes por tanto deben estar
en el único lenguaje que la máquina entiende: el código máquina. Para ello son
necesarios los procesadores de lenguaje cuyo concepto es muy amplio. Dentro de los
procesadores de lenguaje destacan los traductores, los compiladores y los intérpretes.

Un compilador es un programa cuyo cometido es realizar la conversión de un programa


escrito en un lenguaje de programación a su correspondiente equivalente en lenguaje
máquina. El resultado que devuelve un compilador es un programa que ya puede ser
ejecutado por el ordenador destino sin la necesidad de que el compilador esté presente.
Por ejemplo, el lenguaje Pascal o el lenguaje C son lenguajes de programación que
necesitan ser compilados. Cuando la conversión se realiza entre el lenguaje ensamblador
(Assembly) y el código máquina, el compilador recibe el nombre específico de
Ensamblador (Assembler).

Un intéprete es un programa que convierte a código máquina línea por línea el


programa escrito en un lenguaje de programación y que a medida que realiza la
conversión ejecuta las instrucciones . Evidentemente el intérprete no devuelve nada ya
que la ejecución se realiza de forma simultánea. Por este motivo, el intérprete debe estar
presente durante la ejecución. Lenguajes de programación que tradicionalmente son
interpretados son el LISP y el BASIC.

Un traductor es el nombre que reciben aquellos procesadores de lenguaje que


convierten programas de unos lenguajes a otros pero no generan código máquina. Por
ejemplo hay traductores de Pascal a C y viceversa.

Hay otros lenguajes de programación que combinan ambas estrategias como por
ejemplo sucede con el lenguaje de programación Java . Para este lenguaje existen
traductores que generan un programa en un código denominado intermedio que luego
será ejecutado a través de un intérpre que recibe en este caso el nombre de máquina
virtual Java.

Enlazadores

Por simplificación y para facilitar la comprensión de los conceptos anteriores se ha


señalado que los compiladores y los ensambladores (caso particular de compilador)
generan código máquina que puede ser ejecutado por el ordenador. Sin embargo esto no
es totalmente cierto ya que hay una etapa de enlazado que debe ser realizada por otro
programa denominado enlazador (linker). Lo habitual es que durante la escritura de un
programa sea necesario utilizar otros subprogramas en forma de bibliotecas de
funciones o bien que el propio programa esté formado realmente por varios programas
almacenados en diferentes ficheros. Esta situación hace que durante la compilación de
cada módulo no se conozca con exactitud la ubicación de las instrucciones del resto de
programas o bibliotecas de funciones. El papel del enlazador es unir en un único fichero
ejecutable el resultado de todas las compilaciones así como las bibiotecas estáticas de
funciones. Es frecuente que el enlazado sea un paso más de la compilación y que se
ejecute inmediatamente tras la compilación de todos los ficheros.

Es habitual denominar a cada uno de los ficheros que participan en el desarrollo de un


programa con nombres genéricos que identifican en qué fase se encuentran. Por
ejemplo, las instrucciones que escribe directamente el programador, y que forman el
programa en el lenguaje de programación escogido, se conocen como código fuente y se
almacenan en ficheros fuente (source file). El resultado de la compilación de estos
programas se denomina código objeto y se encuentra en ficheros objeto (object file) y
por el último el resultado del enlazado es el fichero ejecutable (executable file). Es este
último el único que puede entender un ordenador sin la presencia del compilador. En el
caso de los lenguajes interpretados el fichero fuente es directamente interpretado y
ejecutado por el intérprete.

Depuradores

Una vez editado y compilado el programa es necesario ejecutarlo (run en inglés), pero
es habitual que durante el desarrollo de una aplicación se generen ficheros ejecutables
que aunque sean correctos desde un punto de vista sintáctico no realicen lo que
realmente se espera de ellos, por lo que no funcionan correctamente. Los depuradores
(debuggers) son capaces de ejecutar el programa paso a paso incluyendo además un
conjunto de facilidades que permiten observar el valor de las variables y estructuras de
datos permitiendo así una mejor localización de errores no evidentes.
Fases en el Desarrollo del Software

Es demasiado frecuente que a la hora de desarrollar un programa o aplicación el


programador empiece a escribir líneas de código como un poseso sin pararse a pensar
qué es lo que quiere hacer, cómo lo va a realizar y qué problemas se va a encontrar.
Elaborar programas con este enfoque es más una tarea artesanal que arroja con alta
probabilidad soluciones inadecuadas. Lo habitual desde el punto de vista de la
ingeniería del software es seguir una metodología con mayor o menor rigurosidad y
precisión que sin duda debe adaptarse a las característcas y a la naturaleza del proyecto.
A grandes rasgos y sin entrar en detalles que se saldrían de los objetivos de este curso,
las fases que permiten llegar desde el planteamiento de un problema a la obtención de la
aplicación informática que lo resuelve son las siguientes:

• Análisis y especificación de requisitos


• Diseño del programa
• Codificación del programa
• Prueba del programa
• Mantenimiento del programa

Análisis y especificación de requisitos

Esta fase es fundamental a la hora de afrontar la resolución de cualquier problema.


Consiste en realizar una descripción clara y completa que suele comenzar con una
descripción textual general que va siendo refinada y concretada hasta culminar con la
enumeración detallada de un conjunto de requisitos. Durante esta fase se pueden utilizar
numerosas técnicas de ánalisis basadas en gran medida en diagramas que representan
los datos, las relaciones que existen entre ellos, el flujo de los mismos y los algoritmos
de procesamiento que los manipulan. El grado de precisión y refinamiento de todos
ellos establece el grado de abstracción del análisis y depende de numerosos factores
entre los que destacan las características del propio problema (no se requiere el mismo
análisis para desarrollar un programa que resuelva ecuaciones de segundo grado que
uno para que controlar el aterrizaje de una aeronave) y la experiencia de los
programadores.

El análisis y la especificación de requisitos proporciona un documento que no solo


permite afrontar la tarea de diseño siguiente sino que además es un documento que
permite que los promotores y usuarios de la aplicación puedan comprobar si el analista
ha comprendido la naturaleza del problema que se pretende resolver. En esta fase, por lo
tanto, es muy importante que participen tanto los desarrolladores como los propios
promotores y usuarios. Esta fase es crucial para el éxito del proyecto y en resumen es la
que permite determinar qué hay que hacer.

Diseño

Una vez que el análisis ha permitido especificar lo que "tenemos que hacer" y los
requisitos que deben cumplirse es momento de determinar cómo lo vamos a realizar.
Hay que determinar el método que vamos a seguir para resolver el problema, qué partes
o bloques va a tener el programa, qué lenguaje de programación se va a utilizar, etc.

Se deben tener en cuenta las siguientes premisas:


• Por un lado procurar, en la medida de lo posible, minimizar el coste, tamaño y
tiempo de ejecución de aquello que se esté desarrollando. No olvidemos que las
empresas y los programadores intentan ganar dinero.
• Por otro lado, obtener la máxima facilidad de uso, fiabilidad, flexibilidad y
sencillez de mantenimiento.

Codificación

Consiste en expresar la solución del problema en un lenguaje de programación. Hay que


destacar que hasta esta fase no se escribe ni una línea de código. Además, si las fases
previas son correctas y completas, el trabajo de codificación suele ser bastante directo.

Prueba

En esta fase, una vez codificado y compilado el programa, se buscan las "cosquillas" al
programa. Lo principal es probar que el programa funciona correctamente según las
especificaciones del cliente. Por ello de nuevo vuelve a tomar importancia la fase de
análisis ya que las pruebas deben estar dirigidas por lo que allí se ha recogido. De
hecho, la fase de prueba suele estar definida durante el propio análisis y en la
codificación se realizan algunas pruebas específicas que permiten obtener un código
más fiable. La fase de pruebas a pesar de que para los programadores noveles no suele
ser una fase muy "atractiva" porque entienden que el producto ya está elaborado, resulta
crucial para que el programa o aplicación pueda ponerse en producción (en uso real) con
las mínimas garantias de seguridad. Durante esta fase se deben evaluar también las
situaciones no previstas en el uso normal pero que puedan producirse durante el uso del
mismo.

Para que se haga una idea de lo importante de esta fase, en las empresas de cierto
tamaño las personas que desarrollan el programa son distintas de las que lo prueban. Y
en aplicaciones con riesgo para la vida humana (hospitales, centrales nucleares,
aeropuertos, etc.) la fase de prueba puede suponer un 80% del tiempo total de
desarrollo.

Tanto durante el proceso de codificación como en el de pruebas la tarea de depuración


del código resulta indispensable. La depuración pretende solucionar problemas
encontrados, lo que no siempre resulta fácil, y es una tarea que debe abordar el propio
programador, lo que dificulta aún más la misma ya que es difícil encontrar los
problemas en el código que ha escrito uno mismo. En esta tarea se distinguen distintas
fases, que suelen ser cíclicas.

1. Localizar la fuente del problema


2. Corregirla
3. Verificar que se ha solucionado el problema

Aprender a depurar el propio código es por tanto uno de los aspectos más relevantes a la
hora de aprender a programar.

Mantenimiento
Una vez que se ha probado suficientemente el programa se le entrega al cliente. Este lo
usa y lo ideal es que en principio quede satisfecho con el resultado. No obstante y a
pesar de todos los esfuerzos, los análisis concienzudos y las pruebas, pueden aparecer
errores que implique labores de mantenimiento correctivo. Por otro lado, con el paso
del tiempo pueden aparecer especificaciones que no estaban contempladas en el análisis
bien porque son nuevas o por cambios en factores externos, dando lugar a la necesidad
de realizar operaciones de mantenimiento adaptativo. Además puede ser prudente
realizar modificaciones en previsión de problemas que aunque no se hayan producido
pueden ser fruto de problemas en un futuro dando lugar a las operaciones de
mantenimiento predictivo.

Desarrollo en cascada

Los ciclos de vida en el desarrollo de una aplicación pueden seguir diferentes enfoques,
aunque en una primera toma de contacto con el mundo de la programación, el modelo
más utilizado es el denominado ciclo en cascada, en el que cada fase se realiza de forma
secuencial pero con cierto grado de solapamiento (se inician etapas antes de culminar
las anteriores) y con carácter cíclico (se vuelve a etapas anteriores). Aunque en el ciclo
ideal, las fases se deben suceder una tras otra, lo normal es que haya la mencionada
realimentación y solapamiento. Sin ir más lejos, si encontramos errores en la fase de
pruebas tendremos que regresar a la fase de codificación, y si el error es de diseño o de
análisis, tendremos que regresar a las primeras fases y replantear nuestra solución. Este
ciclo de vida no es el único pero al nivel de este curso es suficiente.

Durante el ciclo de vida de un desarrollo cada fase genera un conjunto de documentos


que permiten afrontar las fases siguientes y que finalmente constituye la documentación
asociada al proyecto la cual es crucial para afrontar todos las operaciones de
mantenimiento. La documentación debe incluir manuales para los diferentes tipos de
usuarios (administradores, programadores y usuarios finales).
Concepto de Algoritmo

Se define Algoritmo como el conjunto de pasos necesarios para resolver un problema.


Por su naturaleza el algoritmo es previo al programa, de hecho se puede definir
programa como un algoritmo expresado en un lenguaje de programación determinado.
El algoritmo asociado a un problema no es único por lo que conviene analizar en detalle
las diferentes opciones antes de tomar una decisión. El algoritmo debe ser independiente
del lenguaje de programación en el que se quiera desarrollar y de la máquina u
ordenador en la que posteriormente se ejecute el programa, aunque ciertamente a
medida que se desciende en el nivel de abstracción y se concretan los detalles del
algoritmo pueden aparecer técnicas asociadas al lenguaje de programación con el que se
tiene previsto implementar la solución.

El propósito de un algoritmo es comprender perfectamente lo que se va a realizar a la


hora de implementar el programa. Por tanto debe incluir todo lo que se quiera hacer en
el programa y además con un lenguaje perfectamente comprensible, para poder luego
implementarlo en el lenguaje de programación que se desee. El algoritmo deberá incluir
información sobre las variables que se van a utilizar, es decir, los datos que se van a
manejar. Sobre cuándo y cómo se recogen estos datos, sobre qué se va a hacer con ellos
y sobre cuándo se van a devolver los datos o variables al usuario.
De manera que en el algoritmo se representa la interacción del programa con el exterior,
es decir la entrada y salida (E/S) y lo que el programa hace interiormente, todo en un
lenguaje natural, es decir cercano al programador y muy sencillo.

En los algoritmos se suelen distinguir las siguientes partes:

• ESPECIFICACIÓN E INICIALIZACIÓN DE VARIABLES

Aquí debes decir qué variables vas a utilizar, para qué te va a servir cada una y qué
valor inicial, si es necesario, les vas a dar

• RECOGIDA DE DATOS

Se especifica qué datos tiene que introducir el usuario del programa y en qué variables
los vamos a meter

• ACCIONES A LLEVAR A CABO

Aquí hay que contar qué va a hacer el programa

• PRESENTACIÓN DE RESULTADOS

Por último se mostrará al usuario los valores que interese


Todo esto teniendo en cuenta que se debe utilizar el lenguaje natural pero de forma
simple, es decir, utilizando sentencias cortas y claras.

Ejemplo de algoritmo

Se desea resolver el siguiente problema: calcular el valor medio de una serie de


números positivos que se leen desde el teclado. Un valor cero o negativo indicará el
final de la serie. El texto anterior constituye el enunciado del problema que se desea
resolver y por lo tanto es la especificación "en bruto" que debe ser refinada. La
naturaleza de cada problema es diferente y por lo tanto el programador no tiene porqué
conocer los detalles y los métodos asociados a cada problema. Eso hace necesario
añadir información que explique con precisión el proceso al que se someterán los datos
de entrada para proporcionar los resultados de salida. En este ejemplo: El valor medio
de un conjunto de números es el resultado de sumarlos y dividir dicha suma por el
número de elementos. Por lo tanto necesitamos ir contando el número de valores que se
suman e ir acumulando su suma. Con toda esta información se propone el siguiente
algoritmo expresado en un lenguaje "casi-verbal" conocido como pseudocódigo.

Algoritmo:

• Inicio del algoritmo


• Poner el contador de números (Contador) y la suma (Suma) a cero
• Leer un número e introducirlo en Numero
• Mientras el número (Numero) sea positivo hacer
o Sumar Numero a Suma (Suma=Suma+Numero)
o Incrementar en 1 el contador de números, Contador
o Leer un número, introducirlo en Numero
o Fin del mientras
• Calcular el valor medio (Suma/Contador)
• Escribir el valor medio por pantalla
• Fin del algoritmo

Podemos observar que sólo se pasará a calcular el valor medio cuando el número leído
no sea positivo.

Observemos en esta tabla como se van modificando Suma y Contador a medida que
vamos leyendo valores, utilizando para ello una secuencia de números de entrada
cualquiera (3,5,4,9,8,6,-2).

ENTRADA Suma Contador Suma/Contador


0 0
3 0+3=3 0+1=1
5 3+5=8 1+1=2
4 8+4=12 2+1=3
9 12+9=21 3+1=4
8 21+8=29 5+1=5
6 29+6=35 5+1=6
-2 35 6 35/6=5,83

Este ejemplo comentado en detalle sería

• Inicio del algoritmo


• Poner el contador de números (Contador) y la suma (Suma) a cero (Se
van a utilizar las variables Contador, como contador de números
introducidos y Suma para ir almacenando los valores de las sumas,
intermedias y finales, inicialmente el valor de estas dos variables es cero.
Es muy importante identificar el valor inicial que deberán tener las
variables)
• Leer un número e introducirlo en la variable Numero (Se recogerá de la
entrada estándar, el teclado, un número introducido por el usuario)
• Mientras el número (Numero) sea positivo hacer

(Esta instrucción representa un bucle, un conjunto de operaciones que se van a repetir,


ya veremos esta sentencia de control más adelante. Según si el valor de Numero es
positivo o negativo se ejecutan o no las acciones que están dentro de este bucle de tipo
mientras)

o Sumar Numero a Suma (Suma=Suma+Numero) (sumamos este


número a la variable Suma y guardamos el valor en la misma
variable Suma)
o Incrementar en 1 el contador de números, Contador
(Aumentamos Contador en 1, en Contador por tanto se guarda el
número de números, valga la redundancia, que se han leído y
sumado a la variable Suma)
o Leer un nuevo número e introducirlo en Numero (leemos otro
número)
o Fin del bucle Mientras
• Calcular el valor medio (Suma/Contador) (Aquí sólo llegamos cuando el
número que se introduce es negativo, en ese momento dejará de repetirse
la ejecución de acciones dentro del bucle, lo que hacemos es dividir la
suma que hemos ido realizando entre el número de números que hemos
sumado, es decir, la media)
• Escribir el valor medio (Por fin presentamos el resultado por pantalla)
• Fin del algoritmo (Y terminó el algoritmo)

Características de un algoritmo

Un algoritmo debe ser:

• Preciso (instrucciones claras y concretas) y ordenado.


• Determinista (que el resultado sea el mismo al ejecutarlo varias veces con los
mismos datos de entrada).
• Finito (que termine su ejecución bajo las condiciones previstas).

Además, el diseño de un algoritmo:

• Debe ser descendente, de arriba hacia abajo (top-down), dividiendo el problema


en subproblemas.
• Debe presentar un grado de refinamiento sucesivo, es decir, se trata de ir
detallando la descripción en cada paso.
• La representación del algoritmo, de cara a su especificación mediante una
herramienta de programación, se hará mediante diagramas y/o pseudocódigo.

Intentemos explicar estas características con otro ejemplo:

Supongamos que el problema a resolver sea calcular el volumen de un cilindro. ¿Y para


qué? En nuestro caso vamos a instalar unos paneles solares para calentar agua, y
tenemos el tamaño del depósito, pero no el agua que es capaz de almacenar.
Por suerte, revisando el viejo libro de geometría, encontramos que el volumen de un
cilindro es el resultado de multiplicar su base por su altura. ¿Y cuál es su base? Hubo
suerte, en la misma página encontramos que la base se obtiene multiplicando el radio al
cuadrado por la constante PI. ¡Problema resuelto!.

A la hora de trasladar este razonamiento al mundo de la programación comenzaríamos


por dividir el problema en subproblemas, los cuales podían ser:

• Leer datos
• Realizar cálculos
• Escribir resultados

Bien, parece sencillo. Tenemos claramente diferenciadas tres partes del programa.
¡Divide y vencerás!

Ahora se hace necesario ir detallando un poco más las partes anteriores. Esto es lo que
llamamos refinamiento sucesivo. Una posible solución sería la siguiente:

• Leer datos estaría compuesto por otras subtareas que serían:


o Leer Radio r
o Leer Altura h
• Realizar cálculos se descompondría en:
o Calcular base = PI * r * r
o Calcular volumen = base * h
• Escribir resultados quedaría simplemente:
o Escribir volumen
Representación de Algoritmos

Hemos estudiado que un algoritmo debe ser independiente del lenguaje de


programación que posteriormente se utilice (con algunos matices). Esto implica que el
método que usemos para la representación de un algoritmo también debe ser
independiente del lenguaje de programación.

Tradicionalmente se han utilizado dos formas para representar algoritmos, aunque


actualmente existen multitud de técnicas tanto gráficas y textuales que están diseñadas
para representar diferentes aspectos de los algoritmos y de los datos asociados a una
aplicación. No obstante en una primera aproximación al mundo de la programación las
más destacadas son las siguientes:

• Diagramas de Flujo
• Pseudocódigo

La primera de ellas es una forma de representación gráfica de las estructuras de control


que tendrá nuestro programa y que estudiaremos en el tema Estructuras de Control. La
segunda consiste en crear un lenguaje de programación genérico que pueda ser
trasladado con facilidad a cualquier otro lenguaje de programación. Este lenguaje por su
enfoque es un pseudo-lenguaje similar al que hemos usado en los ejemplos previos y
que será el que usemos en este curso.

Diagramas de Flujo

Utiliza símbolos (cajas de distinta geometría) unidos por flechas (líneas de flujo) que
indican el orden o dirección del flujo del programa.

Algunos de los símbolos utilizados son:

En el tema estructuras de control se estudiará la representación mediante diagramas de


flujo de las estructuras de control básicas de la programación.
Programación Modular y Estructurada

En este apartado estudiaremos: los dos paradigmas de programación más utilizados,


aunque no son los únicos, que se basan por un lado en la descomposición de un
determinado problema en módulos independientes (Programación Modular), y la
programación de cada módulo mediante métodos estructurados (Programación
Estructurada).

El primero se fundamenta en el sabio consejo de "divide y vencerás", mientras que el


segundo se fudnamenta en que cualqueir algoritmo puede ser elaborado utilizando
exclusivamente tres estructuras básicas de control . Vamos a desglosar un poco más
estos conceptos.

Programación Modular

En este paradigma:

• El programa se divide en módulos independientes cada uno de los cuales ejecuta una
determinada tarea que resuelve un problema concreto.
• Existirá un módulo denominado módulo principal que será el encargado de transferir
el control a los demás módulos (denominados submódulos). Su función principal es ser
el hilo conductor del programa.
• Al ser los módulos independientes se pueden desarrollar y probar simultáneamente y
con alta independencia. El objetivo es concebir módulos debilmente acoplados
(independientes unos de otros) y con alta cohesión (cada módulo sirve para algo
concreto)
• Las ventajas serán una mayor claridad y legibilidad, gran facilidad para modificar los
programas y reducción del coste del desarrollo, todo ello gracias a la posibilidad de la
reutilización del código (una tarea se escribe una vez y se usa, o invoca, tantas veces
como sea necesario).

Por otra parte, si hay partes o cálculos de nuestro programa que se repiten, se
codificarán como módulo una única vez y se llamará varias veces a ese módulo desde
donde haga falta. Los módulos reciben datos de entrada denominados parámetros que
son procesados internamente para devolver un conjunto de resultados. Obviamente tanto
los parámetros como los resultados no son siempre imprescindibles.

La Programación Modular sigue un diseño descendente (top-down) que significa que


primero se debe especificar qué es lo que se quiere hacer globalmente y a continuación
se va desglosando esa tarea principal en subtareas, cada una de las cuales da lugar a uno
o varios módulos. Esta técnica requiere de un refinamiento sucesivo hasta llegar a un
nivel de subtareas abordables con facilidad

Programación Estructurada

La Programación estructurada parte de la premisa que afirma que cualquier algoritmo


puede ser organizado utilizando exclusivamente tres estructuras de control:

• Secuencial
• Selectiva
• Repetitiva

Como puede comprobar queda prohibido utilizar sentencias de salto incondicional, del
tipo ir al paso X o volver al punto Y. El utilizar las técnicas de la programación
estructurada implica una disminución en el tiempo que se dedica a la verificación,
depuración y mantenimiento de las aplicaciones. Esto implica menor coste en el
desarrollo y mayor calidad en el producto.

Comentario sobre los ejemplos


Es muy frecuente en los libros o cursos de programación encontrar numerosos ejemplos de
problemas matemáticos o científicos. No debemos olvidar que la programación surge en el
entorno de la Ingeniería y que una de las grandes ventajas de los ordenadores es precisamente
el realizar cálculos numéricos a gran velocidad. A pesar de ello, intentaremos eliminar el mayor
número posible de estos ejemplos y sustituirlos por problemas más cotidianos.
Estructura de un programa en Pascal

Antes de continuar tenemos que prevenirle: no se asuste si la cantidad de conocimientos


y conceptos que se le viene encima le parece excesiva. El propósito de este apartado es
proporcionar una visión global de un programa en Pascal. Todavía no tenemos la base
suficiente para comprender en profundidad todos los componentes de un programa, pero
es interesante ver el aspecto global.

La estructura genérica de un programa sería la siguiente:

program nombre_del_programa ;

uses
unidades;

const
const_1 = valor_1;
const_2 = valor_2;
type
tipos_definidos_por_el_usuario;
var
declaración_de_variables;

{** Funciones y procedimientos **}


procedure
definiciones_de_procedimientos;
function
definiciones_de_funciones;
{** Cuerpo del programa **}
begin
sentencias;
end.

Vayamos explicando a continuación cada una de estas partes.

program

Esta palabra marca el principio de un programa y va acompañada del nombre que le


vamos a dar a nuestro programa. Va seguida de un punto y coma que es el separador de
sentencias. Uno de los errores que se debe evitar es utilizar el nombre del programa que
aparece a continuación de la palabra program en otros elementos de nuestro programa,
por lo tanto debe ser único en todo el desarrollo y no debe incluir espacios en blanco ni
caracteres que no pertenezcan al léxico del lenguaje. En el apartado siguiente se
explican las reglas para construir identificadores.

program ejemplo;

uses

Esta palabra reservada va seguida de los nombres de las unidades (units) que utiliza
nuestro programa. Pero, ¿qué son las unidades? Son lo que en otros entornos se conocen
como bibliotecas. Son un conjunto de utilidades de las que un programador puede
disponer para construir su programa. Algunas las proporciona el entorno de
programación y otras se las puede construir usted mismo o las puede proporcionar un
tercero. Esta sección no es imprescindible si no se necesitan bibliotecas o módulos
extra, como verá en el desarrollo de este curso no necesitará utilizarla.

const, type y var

En nuestro programa necesitaremos almacenar nuestros resultados en lo que se llaman


variables y es posible que utilicemos valores (números, letras, etc.) que no cambien
durante la ejecución del programa llamadas constantes. Por último es posible que el
programador se cree estructuras de datos (una forma de agrupar la información)
ajustadas a las necesidades de su programa dando lugar a los denominados tipos
definidos por el usuario.

procedure y function

Cuando en temas anteriores se mencionaba la programación modular se afirmaba que


era conveniente descomponer los programas en partes denominadas módulos o
subprogramas. La forma de descomponer el programa en módulos que proporciona
Pascal son las funciones y los procedimientos.

begin - end

Este es el cuerpo del módulo principal del programa. Como se había indicado
anteriormente este módulo es el que determina el flujo del programa. La instrucción
begin indica el lugar donde comienza a ejecutarse el programa, y la palabra
reservada end marca el punto final del mismo.
Léxico de un programa Pascal

Se denomina léxico de un lenguaje a todas aquellas palabras (tokens) que puede tener un
programa. Con el léxico se construyen los programas en Pascal. Dentro del léxico
destacan:

• Palabras reservadas.
• Identificadores.
• Comentarios.
• Separadores.
• Símbolos especiales.

Palabras reservadas

Reciben este nombre porque tienen un significado especial para el compilador. Ya


hemos visto algunas de ellas: program, var, const, procedure, function, begin, end.

El listado completo de las palabras reservadas en Pascal no es muy extenso, aunque hay
que señalar que los diferentes fabricantes de compiladores han introducido algunas con
objeto de aumentar las prestaciones del lenguaje Pascal. No obstante las que se
consideran Pascal estándard son las siguientes:

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

Identificadores

Los identificadores permiten nombrar o referenciar diferentes elementos en un


programa. El primer identificador que se ha utilizado es el nombre del programa que
aparece junto a la sentencia program. Por otro lado los identificadores permiten
"bautizar" a los subprogramas (procedimientos y funciones), a los tipos de datos y a los
propios datos de cada programa: variables y constantes. Un identificador es una cadena
de caracteres que debe cumplir:

1. Debe comenzar por una letra (a..z o A..Z) y no puede contener blancos.
2. A partir del primer carácter están permitidos dígitos y el carácter de subrayado
(_).
3. No se pueden utilizar palabras reservadas como identificadores

Si nuestro programa intenta calcular el saldo medio de una cuenta corriente,


seguramente necesitaremos un dato para almacenar dicho saldo y su identificador podría
ser:
saldo_medio

Es importante que los identificadores tengan un cierto nombre significativo que refleje
el contenido ya que esto ayuda a la hora de leer y modificar el código. También es
importante destacar que Pascal no distingue entre mayúsculas y minúsculas, por lo tanto
son el mismo identificador saldo que Saldo, SALDO o saldo.

Comentarios

Un comentario es un texto explicativo situado en el código fuente del programa. Este


texto es ignorado por el compilador pero facilita la legibilidad y comprensión del código
por parte de otro programador o del propio autor una vez transcurrido cierto tiempo
desde su desarrollo. En definitiva es una forma de incluir anotaciones directamente
sobre el código del programa.

¿Y cómo distingue el compilador los comentarios del programa? Para que un texto se
considere comentario debe ir encerrado entre (* y *):

(* Este es el formato de comentario *)

O con el siguiente formato adicional en los compiladores de Turbo Pascal:

{ Esto es un comentario }

Los comentarios son de gran importancia para dar claridad al código e imprescindibles
en las fases de puesta a punto y mantenimiento.

Símbolos especiales

Son símbolos formados por uno o más caracteres con un significado específico. Hemos
visto algunos: el punto y coma como separador de sentencias o el punto final que da
lugar al fin de nuestro programa. También forman parte de estos los operadores
matemáticos. El listado completo es el siguiente:

+-*/ =<>[ ] . , ( )
: ; ^ @ { } $ # <= >= := (* *)

Separadores

Para que las palabras reservadas, identificadores o símbolos sean distinguibles unos de
otros hacen falta separadores. Es Pascal se usan como separadores el espacio en blanco,
el tabulador o el carácter de nueva línea (Intro). Además los separadores permiten dar
claridad a la lectura del código.
Mi primer programa

En este apartado editaremos nuestro primer programa en Pascal y aprenderemos a


compilarlo. Esto le permitirá a partir de este punto probar todos los ejemplos del curso.
Para ello será necesario tener instalado en el ordenador un compilador de Pascal. En el
apartado Compilador de este curso tiene el enlace para descargarse un compilador de
Pascal y las instrucciones para su instalación y uso. Para probar este primer ejemplo es
importante seguir el ejemplo que aparece en dicha documentación.

Program Bienvenido;
Const
HOLA='Bienvenido al mundo de la programacion';
Var
nombre: string[40];
begin
write('Introduzca su nombre: ');
readln(nombre);
writeln(HOLA,' ', nombre);
readln;
end.

El método de trabajo recomendado detallado puede encontrarlo en Pasos programa.


Como puede comprobar, es un ejemplo muy simple, pero puede apreciar varias
secciones del programa:

• Var: donde se declara una variable con el identificador nombre


• Const: donde se declara una constante con el identificador HOLA
• Módulo principal o el cuerpo del programa: entre las sentencias begin y end.

Además aparecen sentencias de escritura (write o writeln) y lectura (readln), que


estudiaremos en el siguiente tema.
Si usa el notepad++, editor recomendado, las palabras reservadas que indican secciones
o partes del programa, así como los tipos de las variables, aparecen en azul. Las cadenas
de caracteres aparecen en gris. A la izquierda de cada línea aparece el número de línea
(esto le será muy útil durante la compilación para identificar los posibles errores).

Es importante guardar el fichero con la extensión PAS en el disco duro. Una vez editado
y guardado el programa es necesario compilarlo antes de poder ejecutarlo.

Para ello abra un ventana de comandos, sitúese en el directorio que contiene el fichero
de código y ejecute la orden ppc386 [Link]. (Vea el detalle de cada paso en el
documento antes mencionado)

Si utiliza el entorno integrado para compilar seleccione la opción del menú Execute -
Compile y compruebe si hay notificación de errores en la ventana inferior. Si el error
que aparece es Resource file - Icon file not found (please change it in Project Options se
debe a que la versión de Dev Pascal ha creado el directorio con los iconos con el
nombre equivocado. Consulte este documento de instalación y uso del compilador,
apartado 9, para resolver este problema.

Si durante la compilación aparecen errores, léalos detenidamente y repase su programa.


Es posible que haya tecleado erróneamente alguna palabra reservada, u olvidado algún
punto y coma. Deberá corregir los errores y repetir el proceso tantas veces como sea
necesario (Puede ver el detalle de este proceso en el enlace depuració[Link], también
accesible desde la sección "Materiales de apoyo")

Es muy importante también que los programas tengan un formato determinado, puede
encontrar más información sobre el formato de los programas en
[Link], también accesible desde la sección "Materiales de apoyo".
Tipos de Datos

Comenzaremos diciendo que por dato se entiende la información que el ordenador


maneja para realizar la tarea especificada y obtener los resultados esperados.

Si nuestro programa gestiona las nóminas de la empresa, datos serán los nombres de los
empleados, sus sueldos, direcciones, estado civil, NIF, etc.

Como podemos imaginar, toda esta información no se representa de la misma forma, y


definiremos Tipos de Datos como las distintas maneras existentes de representar la
información. Los datos que el programa está utilizando en un momento determinado se
encuentran en la memoria del equipo en el que se está ejecutando el programa, teniendo
reservado un espacio en dicha memoria. El espacio de memoria reservado para un dato
en particular depende del tipo al que corresponda dicho dato.

Clasificaciones de Tipos de Datos

Podemos establecer diferentes clasificaciones atendiendo a diversos criterios:

• Según su complejidad:
1. Tipos de Datos Simples (o básicos).
2. Tipos de Datos Estructurados (conjunto o agrupación de datos simples
relacionados de alguna forma).
• Según su gestión:
1. Estáticos: aquellos en los que el tamaño está fijado antes de ejecutarse el
programa. El espacio de memoria reservado para ellos no varía a lo largo
de la ejecución del programa.
2. Dinámicos: aquellos en los que el tamaño puede cambiar durante la
ejecución del programa. El espacio de memoria reservado para ellos
puede variar a lo largo de la ejecución del programa.

Realmente hay numerosas clasificaciones, muchas de ellas en función del lenguaje de


programación sobre el que se hagan. Intentaremos ser genéricos y aplicar
posteriormente estas clasificaciones al lenguaje Pascal.

Tipos de Datos Simples

Dentro del conjunto de los tipos de datos simples nos encontramos:

• Numéricos
• Lógicos
• Carácter

Datos numéricos

Se usan para representar el conjunto de valores numéricos y se pueden distinguir dos


tipos:

• ENTEROS: representan un subconjunto finito de los números enteros.


Puede considerar un número entero aquel que no necesita de decimales
para su representación, como por ejemplo, el número de hijos, el número
de habitaciones de un piso, etc.
• REALES: son lo que conocemos como números decimales. Sin ir más
lejos, si representamos el salario en Euros necesitaremos usar un número
real para no perder precisión y poder incluir los céntimos de euro.

En Pascal el tipo entero se corresponde con el tipo integer. Este tipo tiene un rango
finito, lo que significa que no se puede almacenar cualquier número entero ya que la
capacidad está fijada de forma previa. En concreto, los enteros que se pueden
representar incluyen todos los valores desde -32768 hasta 32767, y tal como se ha
señalado no pueden tener decimales.

El tipo real en Pascal se corresponde con el tipo de mismo nombre: real. Se puede
representar este tipo en:

• Notación punto decimal.


La parte entera primero, un punto como separador y la parte decimal.
Importante, el separador de decimales es el carácter punto (no la coma).
Ejemplos:
• 7.3
• 0.125
• 9.0 (para diferenciarlo del entero 9)
• 5,6 ¡ no válido pues utiliza la coma
en vez del punto !

• Notación científica.
La codificación en notación científica o coma flotante consiste en
escribir el número utilizando primero una mantisa (M) multiplicada por
la base 10 (D) elevada a un exponente (exp). D esta forma el número N
cumpla:

N = M x 10exp.

Y esto se representa como M E exp. Ejemplos:

2.345E22 es 2.345 x 1022


9.0E-2 es 9.0 x 10-2

No se preocupe: Para un uso no técnico posiblemente no necesite utilizar esta notación


nunca.

Datos lógicos

Son aquellos que sólo pueden tomar dos valores:

• Valor VERDADERO: Si, Cierto. O sus correspondiente en inglés: true,


on.
• Valor FALSO: No, Falso. O en inglés: false, off.
Este tipo de dato sirve para almacenar información del tipo VERDADERO o FALSO.
Por ejemplo: ¿está la luz encendida? Sólo tenemos dos posibilidades: SI o NO. O, ¿es
usted mayor de edad?. ¿Tiene usted carnet de conducir?. Como vemos, es un tipo de
dato muy frecuente en la vida real.

El comportamiento de este tipo de datos se rige según la lógica booleana, ya que fue el
matemático Boole el que la creó. Como los ordenadores finalmente sólo entienden de
ceros y unos se asocia el valor VERDADERO con el valor numérico 1 y el valor
FALSO con el cero.
El lenguaje Pascal representa este tipo de datos mediante la palabra reservada boolean y
sus dos estados posibles son true y false.

Veremos próximamente las operaciones posibles sobre este tipo de datos, que
generalmente ocupan muy poco espacio en la memoria del equipo.

Datos tipo carácter

Este tipo de datos:

• Representa el conjunto finito y ordenado de caracteres que el ordenador


es capaz de reconocer.
• Aunque no es algo fijo, la mayoría de las veces se utiliza la codificación
con los estándares ASCII o EBCDIC, pudiendo reconocerse los
siguientes subconjuntos:
o Caracteres alfabéticos: a, b, c,...,z, A, B, C,...,Z.
o Caracteres numéricos: 0, 1, 2,...,9.
o Caracteres especiales: +, -, *, /, ^, ;, <, >, $.

En Pascal el tipo carácter se representa con la palabra reservada char.

Existe un tipo muy relacionado con el tipo de datos carácter que se denomina tipo
cadena. Una cadena (también llamada string) es una secuencia de caracteres delimitados
por comillas simple (entre comillas simples). Ejemplo: 'Esto es una cadena', 'Error',
'237'. Por longitud de la cadena se entiende el número de caracteres que componen la
misma.

En Pascal el tipo cadena o string se representa mediante la palabra reservada string. En


el tema de tablas hablaremos nuevamente de este tipo.

Otros tipos de datos:

En función del lenguaje de programación, pueden aparecer otros tipos de datos, que
podrían ser alguno de estos:

• Complejos: pareja ordenada de números reales


• Enumerados: valores de entre un conjunto de enteros
• Subrango: subconjunto de enteros.
• Conjuntos
Pascal sí incluye los tipos enumerados, subrango y conjuntos, aunque no trabajaremos
con ellos en este curso.
Constantes y Variables

Decimos que son constantes aquellos datos que no sufren cambios a lo largo de la
ejecución de un programa. Las variables, por contra, son datos que sí están sujetos a
cambios durante la ejecución.

Constantes

Una definición podría ser la de cualquier valor inalterable que aparece en el programa.
Las constantes pueden ser de distintos tipos que se corresponden con los vistos en el
apartado anterior:

• De tipo numérico
Pueden ser enteras (7777, 43, -34) ó reales (4.321, -32.45)
• De tipo lógico
Pudiendo estar fijadas al valor VERDADERO o al valor FALSO (true/false).
• De tipo carácter
Por ejemplo: 'B', 'o', 'O', '0', '+'.
Dentro de estas se pueden considerar las de tipo cadena:'esto sería una constante
de cadena'

Las constantes pueden no tener un identificador, un nombre que las identifique, en este
caso aparece su valor directamente en el código. Pero por otro lado puede haber
constantes que tengan asignado un identificador, un nombre unívoco que permite hacer
referencia a ellas y por tanto utilizar, tantas veces como sea necesario, su valor
asociado. Normalmente esta asignación se hace al principio del programa, donde se
declaran las constantes que se van a utilizar.

La ventaja de las constantes declaradas con nombre, identificador, es que si el


programador decide modificar el valor asociado no necesita buscar en todo el código del
programa las veces que ha hecho referencia a dicha constante, que en ocasiones son
muchas, para realizar el cambio, sólo es necesario modificar el código allí donde se
declaró la constante y se le asignó valor, que es en una única sentencia del programa

Variables

• Las variables se utilizan para almacenar valores que pueden cambiar en el


transcurso de la ejecución del programa. Sin embargo solamente pueden tomar
valores de un tipo: aquel al que pertenecen (numérico, lógico, carácter).
• Se designan mediante un identificador. El identificador o nombre de una
variable estará compuesto por varios caracteres, no debiendo coincidir con
ninguna palabra reservada y cumpliendo las normas de los identificadores.
Normalmente el primer carácter será una letra. El nombre de la variable es
recomendable que tenga relación con aquello que representa (velocidad,
resultado, resultado_suma, volumen).
• Para poder utilizar una variable es necesario haberla declarado previamente.
Declarar una variable es sencillamente dar cuenta de su existencia
explícitamente en algún lugar del programa dedicado a tal efecto.
• La declaración de una variable reserva la memoria necesaria para almacenar un
dato del tipo de la variable, la cantidad de memoria reservada dependerá, por
tanto, del tipo declarado.

En el lenguaje Pascal la forma de definir variables y constantes con nombre es la


siguiente:
const
const_1 = valor_1;
const_2 = valor_2;
var
var_1: tipo1;
var_2: tipo2;
donde const_1 y const_2 son los identificadores (nombres) de las constantes, valor_1 y
valor_2 represetan los valores que se asignan a las constantes con nombre. var_1 y
var_2 son los identificadores (nombres) de las variables y tipo1 y tipo2 son los tipos de
dichas variables (entero, real, lógico, carácter...)
Ejemplos
Const
iva = 18;
irpf = 15;
euro = 166.386;
error = 'Algo ha salido mal...';
Var
velocidad: real;
resultado: boolean;
letra: char;
NumHijos: integer;
Si recordamos nuestro primer programa es fácil identificar las constantes y la variables
que aparecen en el mismo.
Program Bienvenido;

Const
HOLA='Bienvenido al mundo de la programacion';
Var
nombre: string[40];
begin
write('Introduzca su nombre: ');
readln(nombre);
writeln(HOLA,' ', nombre);
end.

Variables locales y globales

Según el lugar del programa donde se declaran las variables pueden ser:

• Variables globales: Se declaran al principio del programa, antes de la


declaración de cualquier módulo. Se pueden utilizar en cualquier punto de
nuestro programa, es decir cualquier módulo tiene acceso a la zona de memoria
que esta variable tiene reservada.
• Variables locales: Se declaran justo al principio de cada módulo (principal,
procedimiento o función), y sólo pueden utilizarse en dicho módulo, es decir que
sólo el módulo en el que fue declarada la variable tiene acceso a la zona de
memoria reservada para ella. Por lo general esta zona de memoria se libera
cuando el módulo termina de ejecutarse. Si desde un módulo se quiere utilizar la
variable declarada en otro será necesario, como se verá más adelante, que se le
especifique al otro módulo la zona de memoria en la que se encuentra dicha
variable. En el curso se verá más adelante que este procedimiento se denomina
paso de parámetros por referencia.

A lo largo del curso irá viendo que se recomienda no utilizar variables globales. Esto es
porque así se asigna a un determinado módulo del programa la responsabilidad sobre la
gestión de dicha variable, manteniendo el programa más seguro.
Expresiones

Bien, ya sabemos que son las variables y las constantes. Pero poco podemos hacer con
ellas solas. Necesitamos usarlas y operar con ellas para obtener resultados. Por ejemplo,
si está haciendo la factura de una venta, necesita calcular el IVA del importe de la
misma. Y para ello necesitamos lo que se conocen como operadores. Los operadores,
junto con las variables y constantes, formarán lo que se conoce como expresiones.

Expresiones Aritméticas y Lógicas

Con mayor precisión, una expresión es una combinación de los siguientes elementos:

1. Constantes
2. Variables
3. Símbolos de operaciones más conocidos como operadores
4. Paréntesis
5. Llamadas a funciones (módulos que devuelven un valor como resultado)

Ejemplos de expresiones que estamos acostumbrados a utilizar son:


total = factura + factura * 0.18;

nota = (nota_teoria + nota_practica)/2;

Se puede resumir que:

• La expresión, al evaluarse, da como resultado un valor.


• En las expresiones podemos encontrar operandos (factura, 0.18) y operadores
(como por ejemplo: +, *, /, =).
• Se pueden clasificar las expresiones según el tipo de dato asociado al valor que
producen al evaluarse. Así tendremos operaciones aritméticas (cuando el
resultado es de tipo numérico), operaciones lógicas (cuando el resultado es de
tipo lógico), operaciones de tipo carácter (cuando producen un resultado de este
tipo).

Expresiones Aritméticas

Son aquellas en las que el resultado y los operandos son de tipo numérico. A muchos de
estos operadores ya estamos acostumbrados: suma, resta, producto, división, etc.
+, -, *, /
Suma, resta, multiplicación y división. Aplicadas sobre enteros dan como
resultado un entero, y sobre reales un real. Si alguno de los operandos es
real el resultado es real.
div
División entera: calcula el cociente entero.
9 div 2 daría como resultado 4.
mod
Calcula el resto de la división entera.
9 mod 2 daría como resultado 1.

Expresiones Lógicas
Como ya hemos apuntado, son aquellas que producen un resultado de tipo LÓGICO.
Los operadores lógicos actuarían sobre operandos del mismo tipo. Tendríamos:
O (operador or, suma booleana)
Este operador da como resultado VERDADERO si cualquiera de los dos
operandos es VERDADERO. Por lo tanto, sólo será FALSO si los dos
operandos son FALSO.
Y (operador and, producto booleano)
Este operador da como resultado verdadero sólo si los dos operandos son
VERDADERO. En cualquier otro caso el resultado es FALSO.
NO (operador not, negación booleana).
Cambia el valor lógico sobre el que se aplica, y lo convierte en VERDADERO
si era FALSO, o en FALSO si es VERDADERO.
En esta tabla presentamos el resultado de estos operadores:
x y xOy xYy NO x
FALSO FALSO FALSO FALSO VERDADERO
VERDADERO FALSO VERDADERO FALSO FALSO
FALSO VERDADERO VERDADERO FALSO
VERDADERO VERDADERO VERDADERO VERDADERO

Y utilizando los operadores y constantes que corresponden en PASCAL tenemos:

x y x or y x and y not x
False False False False True
True False True False False
False True True False
True True True True

Dentro de los operadores LÓGICOS hay que considerar también los operadores
relacionales que actúan sobre operandos de tipo NUMÉRICO y de tipo CARÁCTER, y
producen resultados de tipo LÓGICO. Son los siguientes:

> mayor que


< menor que
>= mayor o igual
<= menor o igual
= igual
<> distinto
El resultado sobre operandos de tipo NUMÉRICO es intuitivo:
7 > 3 produce como resultado VERDADERO
3 = 5 produce como resultado FALSO

Para comparar operandos de tipo CARÁCTER se supone que los mismos se encuentran
ordenados de tal manera que:

'A' < 'B' < 'C' <.......< 'Z'


'a' < 'b' < 'c' <........< 'z'
'0' < '1' < '2'.....< '9'

Por lo tanto
'c' > 'm' da como resultado FALSO

Expresiones de tipo Carácter

Si nos basamos en la ordenación de los caracteres, se pueden utilizar los operadores + y


-. Al sumar o restar un entero n a un carácter, el resultado será el carácter que se
encuentre n posiciones por encima (+) o por debajo (-) del carácter original, tomando
como base los criterios de ordenación anteriormente descritos.

Como ejemplo tenemos que la expresión 'A' + 2 da como resultado 'C'.


Operaciones Básicas con Datos Simples

Básicamente son tres las operaciones que podemos realizar:

1. Asignación
2. Lectura
3. Escritura

Asignación

Sentencia mediante la cual se le da un valor a una variable. La sentencia de asignación


tiene un carácter destructivo sobre el contenido previo de la variable dado que la
variable pierde el valor que anteriormente tenía al serle asignado un nuevo valor.

La sentencia de asignación utiliza el símbolo :=. Observe la forma de usarlo:

variable := expresión

Por ejemplo, si queremos vender un producto y le queremos aplicar al cliente un


descuento del 10% al sobre el precio de venta al público (PVP) obtendremos:

precio_final := PVP - (PVP*0.10);

El símbolo de asignación := no tiene por que ser el mismo en otros lenguajes de


programación. Sin ir más lejos, en C se utiliza sólo el carácter = ¡Pero cuidado!
Recuerde que en Pascal el = es un operador lógico.

precio_final = PVP - (PVP*0.10); (* No funciona en Pascal


*)

Además la asignación en lenguaje C en lugar de una sentencia es un operador. Esta


diferencia y sus repercusiones se estudian en profundidad en lenguaje C. En Pascal hay
que tener en cuenta que al tratarse de una sentencia y no de un operador no es válido
hacer asignaciones en cadena del tipo:

variable:=variable:=expresion; (* No funciona en Pascal *)


A la hora de programar en pseudocódigo (que recordemos que intenta ser una notación
común e independiente del lenguaje de programación), se recurre a una notación
simbólica y el operador de asignación se representa mediante una flecha apuntando a la
izquierda, <-
precio_final <- PVP - (PVP*0.10); (* Esto es
Pseudocódigo, NO Pascal *)

La asignación se realiza en dos pasos:

1. Primero se evalúa la expresión a la derecha del símbolo de asignación.


2. A continuación se almacena el valor resultante en la variable que se encuentra a
la izquierda del símbolo de asignación.
Hay que tener en cuenta las siguientes observaciones:

• Si no se le asigna ningún valor a una variable ésta tendrá un valor


indeterminado y dará error si intentamos utilizarla. Por ello recuerde que
siempre es imprescindible darle un valor inicial a una variable (inicializarla)
antes de utilizarla.
• La expresión a la derecha del símbolo de asignación debe producir un resultado
del mismo tipo que la variable a la izquierda del símbolo de asignación.
• Si el resultado de la expresión excede el rango de la variable se produce lo que
se denomina como desbordamiento (overflow). Recuerde por ejemplo que los
enteros convencionales de Pascal no pueden superar el valor 32767.
• Otro error bastante corriente es intentar realizar una operación de división por
cero. El error se produce por indefinición de la operación pero no se detecta por
el compilador sino que se produce en tiempo de ejecución del programa y
lamentablemente lo detecta el usuario final si el programador no ha realizado las
pruebas suficientes. Por este motivo, siempre que se hacen divisiones, es
necesario comprobar si en algún caso el denominador podría llegar a ser cero
para evitar el error.

Lectura y Escritura

Entendemos por operaciones de lectura y escritura a las operaciones de entrada y salida


de información desde el "exterior" al ordenador y viceversa.

El ordenador se comunica con el entorno que le rodea mediante lo que se conocen como
periféricos. Estos son los dispositivos que permiten que la información vaya del
ordenador al exterior y en sentido contrario.

Son periféricos el teclado (que permite que demos órdenes al ordenador, o en general
que introduzcamos información), la pantalla (que permite al ordenador presentar el
resultado de sus programas), la impresora, los altavoces, el ratón, una pantalla táctil, etc.
También se puede considerar un periférico el disco duro del ordenador, en el que un
programa puede almacenar información en ficheros, para más tarde recuperarla.

Las operaciones de lectura y escritura le dicen al ordenador que debe "capturar"


información del exterior o que debe presentar información al exterior.

Desglosemos a continuación cada una de ellas de forma genérica:

1. Operación de Lectura:
o Se toma un valor (o varios) de un periférico y se asignan a una
variable (o a varias variables) en el orden de aparición:
o LEER nombre_var1, nombre_var2

oEl periférico por defecto es el teclado, es decir, cuando no se dice


expresamente de dónde queremos leer indicamos que deben
tomarse los datos del teclado.
2. Operación de Escritura:
o Se evalúan una (o más) expresiones y se envían a un periférico:
o
o ESCRIBIR exp1, exp2

o Estas expresiones pueden ser de cualquier tipo: si son variables se


imprimirá el valor de las mismas; si son cadenas de caracteres
constantes se imprimirán tal cual.
o El periférico por defecto es la pantalla de la máquina. Si
deseamos escribir en cualquier otro periférico, por ejemplo en
una impresora, tendríamos que especificarlo explícitamente:
o ESCRIBIR EN IMPRESORA exp1,
exp2.

Estas operaciones de lectura y escritura se realizan en Pascal mediante las funciones


read y write.

función write

La función write (escribir) presenta por pantalla lo que le indiquemos entre sus
paréntesis. De hecho, en la lección anterior se usó en nuestro primer programa:
write('Bienvenido a este curso de Programación');

Este sería su uso más sencillo. Pero es más interesante presentar por pantalla el valor
almacenado en variables:

write('Su nombre es: ', nombre);

que imprime la cadena Su nombre es: seguida del valor almacenado en la variable
nombre, que en el caso de que nombre contenga el valor 'Marisa' mostraría por pantalla
el resultado:

Su nombre es: Marisa


Se puede intercalar texto y variables separados por el carácter coma (,):
write('Su nombre es :', nombre, '. Hola.');
Que dará como resultado:
Su nombre es: Marisa. Hola.

O separarlo en varias sentencias:

write('Su nombre es :');


write(nombre);
write('. Hola.');

Cuando se desea seguir escribiendo en la siguiente línea se utiliza la función writeln(),


que tras escribir sus argumentos pasa a la siguiente línea. Es similar al "retorno de
carro" de las máquinas de escribir.

write('Su nombre es :');


writeln(nombre);
write('.Hola.');
Que ahora dará como resultado:
Su nombre es: Marisa
.Hola.

función read

La función read (leer) lee lo que el usuario escriba con el teclado y lo almacena en la
variable que le indiquemos entre sus paréntesis.

read(nombre);

Este sería su uso más simple. Se pueden leer varios valores, y las variables donde se
almacenen deben estar separadas por el carácter coma (,):

read(nombre, edad);

La sentencia read (y readln) espera a que se pulse la tecla Intro (Retorno de Carro,
Enter, Return) antes de asignar los valores escritos a las variables.

Lo normal es intercalar funciones de escritura y lectura para informar al usuario de qué


información es la que se le está solicitando que introduzca:

write('Introduzca su nombre');
read(nombre);
write('introduzca su edad');
read(edad);

La sentencia readln() tiene un funcionamiento diferente al de writeln(). Las sentencias


read() y readln() no asignan nada a las variables hasta que el usuario pulsa la tecla
Enter. ¿Qué ocurre si tecleamos más valores de los esperados?

• Con la función read, estos se quedan "pendientes", esperando ser leídos por la
próxima sentencia read (si la hay).
• En cambio, si se le proporcionan a readln más valores de los que espera
descarta todos los que le sobran (los últimos).

Veamos este comportamiento con un ejemplo en el que aparecen dos elementos nuevos
cuya misión es evitar que la ventana de ejecución del programa se cierre una vez
finalizado el programa impidiendo que se visualice el resultado. Estos dos elementos
nuevos son la declaración de la unidad crt en el epígrafe uses y el procedimiento
readkey que espera a que el usuario pulse una tecla:
Si compilamos y ejecutamos según se presenta en la siguiente figura:

se asignará

edad = 44
peso = 68
y se queda pendiente de leer el valor 72 que se asigna a altura a continuación:
altura = 72

En cambio con el uso de readln y los mismo datos de entrada:


Si compilamos y ejecutamos según se presenta en la siguiente figura:

se asignará

edad = 44
peso = 68
se descartara el valor 72, y se le asigna a continuación el valor 1.75 a la altura:
altura = 1.75

Podemos observar que la sentencia write que presenta el valor de las variables tiene un
formato novedoso:

writeln('Edad: ', edad, ' Peso: ', peso, ' Altura: ', altur[Link]);
El formato en el que se presentan los tipos numéricos puede ser modificado
especificando el número de caracteres que se usarán para imprimirlo (4 en este caso) y
el número de estos que serán decimales (2).

Si no se especifica formato, se utiliza su longitud con un espacio en blanco delante si es


positivo o un signo menos si es negativo. Los números reales se escriben por defecto en
notación científica.

Ya conocemos como usar constantes, como asignar valores a variables y como leer o
escribir mediante las funciones de entrada y salida. En el tema siguiente estudiaremos
como podemos modificar la ejecución de nuestro programa mediante las estructuras de
control.
Sentencias Selectivas

Estas estructuras, también llamadas bifurcativas, condicionales o alternativas, dividen o


ramifican el flujo del programa según una determinada condición. Pero, ¿qué es una
condición?
Una condición es una expresión que da como resultado un valor del tipo lógico o
booleano (verdadero/falso, true/false, 1/0). Este concepto se introdujo al estudiar los
tipos de datos.
¿Por qué puede ser interesante bifurcar el flujo un programa? Para que el programa se
comporte de forma distinta en función de la evaluación de la condición. Por ejemplo, si
una persona es mayor de edad o no (edad>=18), el rango en el que está su nivel de
ingresos ((ingresos>=1000) and (ingresos<2000))…

Tipos de sentencias selectivas

Podemos encontrar tres tipos de sentencias selectivas:

• Simples
• Dobles
• Múltiples

Los apartados siguientes se basan en un formato común:

• Primero se introduce el concepto genérico de las distintas estructuras


acompañadas de sus diagrama de flujo, aplicables a cualquier lenguaje de
programación.
• Al mismo tiempo se explica cómo se implementan estas estructuras, que son
comunes a todos los lenguajes de programación estructurados, en un lenguaje
concreto: Pascal.
• Finalmente, a cada tipo de sentencia le acompaña un ejemplo.

Selectiva Simple

De las estructuras selectivas, la más sencilla es la selectiva simple. Se evalúa una


condición; si es verdadera (true) se ejecuta una sentencia (o grupo de sentencias, que
podríamos denominar sentencia compuesta). Si es falsa, se "salta" dicha sentencia y se
sigue ejecutando el programa.
La expresión de la condición puede ser compleja, pero debe dar como resultado un valor
booleano: true o false. La representación gráfica de esta estructura, para cualquier
lenguaje de programación, es la que se puede observar en esta figura:
Observemos la figura:

• Las flechas representan en qué sentido va


ejecutándose el programa (el flujo, orden, de
las acciones del programa).
• El rombo simboliza la evaluación de la
condición lógica. Observe que de dicho
rombo salen dos flechas, etiquetadas como Sí
y No. El flujo del programa continuará por
una u otra rama según el resultado de la
evaluación de la condición del rombo (por la
de Sí el resultado es true, por la de No si es
false).
• La caja cuadrada representa la sentencia (o
grupo de sentencias) que se ejecutan si la
condición es verdadera.

En Pascal, se logra este efecto con la sentencia if-then:


if (condición) then
sentencia_a;
Por ejemplo, los bancos actualizan el saldo de nuestras cuentas corrientes de forma
periódica, aplicando un cierto interés:
if (saldo > 0) then
saldo := saldo * 1.02;
Si la sentencia es compuesta deberá comenzar y terminar dicho conjunto de sentencias
con las etiquetas begin-end, con su correspondiente ;.
Continuando con el ejemplo anterior, muy posiblemente el banco también comprueba si
estamos en números rojos, aplicando el correspondiente interés:
if (saldo < 0) then
begin
saldo := saldo * 2.20;
writeln('Saldo Negativo');
end;

Selectiva Doble

La selectiva doble es un mejora de la sentencia if-then: Si la condición es verdadera se


ejecuta un conjunto de acciones (1), y si la condición es falsa se ejecuta otro conjunto
distinto de sentencias (2). Es importante señalar que, una vez ejecutado el conjunto de
sentencias (1) o (2), el flujo del programa se reúne o encuentra, y se sigue ejecutando el
código secuencialmente. En PASCAL se logra este efecto añadiendo la sentencia else a
la ya conocida sentencia if-then:
if (condicion) then
sentencia_a
else
sentencia_b;
No olvidemos que cualquiera de las sentencias puede ser una sentencia compuesta, con
su correspondientes begin-end
if (condicion) then
begin
sentencia_a_1;
sentencia_a_2;
sentencia_a_3;
end
else
sentencia_b;
Observe el comportamiento mencionado en la siguiente figura, que es muy similar a la
previa:

Observe la única diferencia con la estructura


de control anterior: En la bifurcación (a veces
se le llama rama o brazo) correspondiente al
No aparecen un conjunto de sentencias.
Insistiendo con nuestra relación con el banco, le mostramos un ejemplo de la estructura
selectiva doble:
if (saldo < 0) then
begin
saldo := saldo * 1.20;
writeln('Saldo Negativo');
end
else (* (saldo > 0) *)
begin
saldo := saldo * 2.02;
writeln('Saldo Positivo);
end

Le presentamos como segundo ejemplo de esta estructura de control una sección de


código del programa Euros. Este programa traslada cantidades de pesetas a euros o
viceversa. La parte principal de este programa es la siguiente:

if (opcion='P') then
begin (* Ejemplo de uso de sentencia compuesta *)
write(canti[Link]); (* 10:3, formate el resultado
limitando la anchura a 10 caracteres y tres decimales.*)
write(' euros son ');
resultado:=cantidad*EURO;
write(resultado:10:3);
write('pesetas.')
end (*No se terminan con ;*)
else
if(option='E')then
begin
resultado:=cantidad/EURO;
writeln(canti[Link],'pesetas son', resultado:10:3,
'euros.');
end;
writeIn('Opcion no permitida');
Debe tener precaución con el terminador de sentencia (;) y el brazo else: Nunca ponga
un ; antes de un else puesto que el compilador pensaría que la sentencia if ha terminado
y mostraría un error al compilar, pues no reconoce la sentencia else. Esta precaución
esta comentada en el ejemplo previo.

Selectiva Múltiple

Dentro del conjunto de las selectivas se incluye la que algunos autores llaman selectiva
múltiple. Esta permite seleccionar la ejecución de una sentencia entre más de dos
alternativas. A diferencia de las selectivas anteriores, en vez de una condición se evalúa
una expresión que da como resultado un valor de tipo ordinal, un entero o carácter. Una
vez obtenido este valor, que llamaremos selector, se compara con los distintos valores
de las distintas alternativas. Cada una de estas alternativas tiene asociada una sentencia,
simple o compuesta. En el momento que coincida el valor del selector, se ejecuta la
sentencia asociada a esa alternativa y termina la ejecución de la selectiva múltiple,
continuando la ejecución del programa al final de esta. Si terminamos de comparar
todas las alternativas y no coincide con ninguna, se ejecuta lo que se conoce como
acción o sentencia por defecto. Esta sentencia se puede omitir. Este comportamiento se
refleja con el siguiente diagrama de flujo:
En esta figura:

• En el rombo se evalúa la expresión,


obteniendo el selector.
• El selector se va comparando con las listas de
valores que tenemos en cada uno de los
brazos de la selectiva múltiple.
• En el momento que coincida con alguno de
ellos, se ejecutan las sentencias que hay en
esa rama y se salta el resto de la estructura.
• Si el selector no coincide con ninguno de los
valores de los brazos, se ejecutan las
sentencias por defecto, que como observamos
se representa como última opción.

En Pascal la estructura selectiva múltiple se corresponde con la sentencia case-of. Las


distintas alternativas se especifican mediante etiquetas. Una etiqueta es una lista de
constantes separadas por comas. Las etiquetas están separadas de las sentencias que le
corresponden mediante el carácter ':'. La sentencia por defecto se marca con la palabra
reservada else.
case (selector) of
etiquetas_1: sentencia_1;
etiquetas_2: sentencia_2;
.
.
etiquetas_n: sentencia_n;
else
sentencia_por_defecto
end (* se corresponde con el case *)
Una sección de código del programa Calc. Este programa realiza las operaciones
básicas de una calculadora: sumar, restar, multiplicar y dividir. Observe las palabras
reservadas case-of-else-end.
case (opcion) of
'S','s' : resultado:= primero+segundo;
'R','r' : resultado:= primero-segundo;
'M','m' : resultado:= primero*segundo;
'D','d' : resultado:= primero/segundo;
else
writeln ('Opción no permitida');
end;

Selectivas anidadas

Cuando alguna de las sentencias que aparece dentro de los brazos o alternativas de una
sentencia selectiva es otra sentencia selectiva, se dice que están anidadas. No hay límite
al número de sentencias que se pueden anidar, siempre que estén totalmente incluidas
unas en otras, como en el ejemplo del programa Euros que se había presentado
anteriormente. Si existen estructuras if anidadas, las palabras reservadas else se
corresponden con el if inmediatamente anterior, el más cercano. En el siguiente
ejemplo, sección de código del programa Banca, se vuelve a observar la importancia de
sangrar (tabular) correctamente el código:

actualizar := false;
saldo := 7500;

if (saldo > SALDOMIN) then

if (actualizar) then

saldo := saldo * 1.02 (* Actualizamos un 2% *)

else (* MAL tabulado !!*)

writeln('No alcanza el saldo minimo');

Se puede pensar que con más de 7500 euros de saldo (SALDOMIN) se imprime el
mensaje de aviso No alcanza el saldo minimo . Pero si compila y ejecuta este programa
comprobará que esto no es cierto. ¿Qué está ocurriendo? Simplemente, el else se asocia
con la sentencia if más cercana. La tabulación del código nos hace creer que se asocia al
primer else. Si quisiera que se correspondiese con el primero deberá usar los
delimitadores de bloque o sentencia compuesta begin-end,como puede ver en el fichero
Banca2:
if (saldo > SALDOMIN) then
begin
if (actualizar) then
saldo := saldo * 1.02;(* Actualizamos un
2% *)
end
else
writeln('No alcanza el saldo minimo');
Antes de pasar a estudiar las siguientes estructuras de control, estudie el código
completo de los ejemplos anteriores:Euros, Calc, Banca y Banca2. Le animamos a que
los pruebe, modifique y mejore.

Program Euros;
(*
Programa de ejmplo del uso de selecticas dobles y anidadas.

Pasa cantidades de euro a pesetas y vicecersa.

*)

Const
EURO=166.368; (* Valor de 1 euro en pesetas *)

Var
opcion: char; (* a Pesetas o a Euros *)
cantidad: real; (* Cantidad a calcular *)

begin

write('Introduzca la cantidad a convertir: ');


readln(cantidad);

write('Convertir a Pesetas o a Euros (P/E)?: ');


readln(opcion);

if (opcion='P') then
begin (* Ejemplo de uso de sentencia
compuesta *)
write(canti[Link]);

(* 10:3, formatea el resultado limitando la anchura a 10 caractereres


y tres decimales *)

write(' euros son ');


write(cantidad*EURO);
write(' pesetas.')
end
else
if (opcion='E') then
writeln(cantidad,' pesetas son ', cantidad/EURO:10:3, '
euros.')
else
writeln('Opcion no permitida');

end.

Program Calc;
(*
Ejemplo del uso de selectiva multiple.
Solicita al usuario dos números, y la operación a realizar sobre
ellos:
sumar, restar, multiplicar o dividir.
*)

Var
opcion: char; (* Para comprobar si desea continuar el
usuario *)
primero: real; (* Primer operando *)
segundo: real; (* Segundo operadno *)
resultado: real; (* Resultado final *)

begin
write('Introduzca el primer operando: ');
readln(primero);

write('Introduzca el segundo operando: ');


readln(segundo);

writeln(' Opciones: S(sumar), R(restar), M(multiplicar),


D(dividir)');
readln(opcion);

case (opcion) of
'S','s' : resultado:= primero+segundo;
'R','r' : resultado:= primero-segundo;
'M','m' : resultado:= primero*segundo;
'D','d' : resultado:= primero/segundo;
else
writeln ('Opcion no permitida');
end;
writeln('El resultado es ', resultado:10:3);
end.

Program Banca;
(*
Ejemplo de uso de selectiva doble
Observe que el código está mal sangrado intencionadamente
*)

Const
SALDOMIN=10000;
Var
saldo: real;
actualizar: boolean;
begin
actualizar := false;
saldo := 7500;

if (saldo > SALDOMIN) then


if (actualizar) then
saldo := saldo * 1.02 (* Actualizamos un 2% *)
else (* MAL tabulado !! *)
writeln('No alcanza el saldo minimo');
end.
Program Banca;
(*
Ejemplo de uso de selectiva doble
Observe que el código está mal sangrado intencionadamente
*)

Const
SALDOMIN=10000;
Var
saldo: real;
actualizar: boolean;
begin
actualizar := false;
saldo := 7500;

if (saldo > SALDOMIN) then


begin
if (actualizar) then
saldo := saldo * 1.02; (* Actualizamos un 2% *)
end
else
writeln('No alcanza el saldo minimo');
end.
Sentencias Repetitivas o Bucles

Estas estructuras, también llamadas iterativas, provocan que un conjunto de sentencias


del programa se repita un determinado número de veces. El número de estas
repeticiones puede estar prefijado de antemano, o depender de la evaluación de una
condición. A estas estructuras se las conoce como bucles. Cada vez que se ejecuta 1 vez
el conjunto de instrucciones del bucle se dice que se ha producido una iteración.

Imagine que quiere aparcar el coche en la puerta de casa, y no hay sitios libres: daremos
vueltas a la manzana hasta que haya un hueco libre. Este es un ejemplo de estructura
repetitiva: repetir una acción (dar una vuelta a la manzana) hasta que se cumpla una
determinada condición (que haya un hueco libre).

O tareas tan simples como descargar el coche después de la compra: Repetimos un


conjunto de acciones (sacar bolsa del coche, llevarla a la cocina, repartir la compra en
las estanterías) mientras se cumpla una condición (que queden bolsas en el coche).

Incluso si hace deporte, y corre por las mañanas en su parque preferido, posiblemente
utilice una estructura repetitiva: dar una vuelta al parque (acción que se repite) hasta que
pasan 30 minutos, o estemos muy cansados, o empiece a llover (condición del bucle).
En este caso la condición de salida del bucle es más compleja: es una condición lógica
compuesta, conectada con el operador lógico O (OR en inglés). Recuerde que con este
operador la condición será verdadera (true) si cualquiera de las condiciones es cierta. Si
tiene dudas, repase el tema tipos de datos y operadores.

Tipos de sentencias repetitivas

Según como se controle la ejecución del bucle encontramos tres tipos de sentencias
repetitivas:

• Desde
• Mientras
• Hasta

El bucle DESDE
Este bucle se utiliza cuando de antemano conocemos el número de veces que se tiene que
repetir el conjunto de sentencias. Imagine que en el ejemplo de correr por el parque por las
mañanas, la condición fuera dar un número fijo de vueltas al parque , llueva o estemos
cansados. La condición de finalización del bucle será que el número de vueltas realizadas sea
mayor o igual que el prefijado.

En este tipo de bucles necesitamos:

• una variable de control o variable índice que controla el número de veces que se repite
un bucle (número de iteraciones).
• fijar un valor inicial para la variable de control.
• fijar el valor límite que tomará la variable de control.

El funcionamiento del bucle es el siguiente:

1. La variable de control toma el valor inicial.


2. Se compara dicho valor con el valor final
3. Si es mayor, se termina la ejecución del bucle.
4. Si es menor o igual,
a. Se ejecuta las sentencias que forman parte del bucle.
b. Se incrementa la variable de control (autoincremento). Esto lo realiza de forma
automática el bucle.
c. Ir a 2.

Lo que está totalmente desaconsejado es modificar la variable de control dentro del


bucle. Si necesita hacerlo, posiblemente el bucle DESDE no es el adecuado.

La representación gráfica de esta estructura para cualquier lenguaje de programación es


la siguiente:

En esta figura:

• En el símbolo inicial (mezcla de rombo y caja) se fijan el


valor inicial de la variable de control, y el límite de esta.
También es el lugar donde se evalúa la condición para
que se ejecute el bucle: que la variable de control sea
menor o igual que el valor límite o final.
• Si la condición se cumple:
o Se ejecutan las acciones especificadas en el
bucle.
o Una vez ejecutas estas, se incrementa la variable
de control. Este incremento es automático, lo
hace la propia estructura, y no hay que
codificarlo. Se representa con el símbolo
etiquetado como autoincremento índice.
• Si la condición no se cumple, termina la ejecución del
bucle, lo que se representa con el brazo etiquetado como
NO en la figura.

En PASCAL, se logra este comportamiento con la sentencia for:

for v_control := valor_inicial to final do sentencia_a; O para el caso que queramos ir de


mayor a menor, de "cuenta atrás": for v_control := valor_inicial downto final do
sentencia_a; Como ejemplo inicial, observe un bucle que imprime por pantalla el
mensaje 'Bienvenido a este curso' diez veces.

for i:= 1 to 10 do

writeln('Bienvenido a este curso');

O si desea un conjunto de acciones, utilizamos el par begin-end. Observe en ambos ejemplos


la variable de control, i; valor inicial, 1; valor final, 9.

for i:= 1 to 9 do

begin

writeln('Bienvenido a este curso');


writeln(' Introduccion a la Programacion');

end;

Lo que lo hace realmente potente al bucle DESDE es la posibilidad de usar el valor de


la variable índice dentro de las sentencias del bucle.

Como ejemplo se presenta el siguiente fragmento de código:

Sección de código del programa Sumar

begin

writeln('Este programa suma los numeros entre dos valores');


writeln('Introduzca el primer operando: ');
readln(primero);

writeln('Introduzca el segundo operando: ');


readln(segundo);
suma := 0; (* Hay que iniciar a cero antes de usar por primera vez su valor en
suma:=suma+indice*)
for indice:= primero to segundo do

suma := suma + indice; (* Aqui se usa la variable de control indice*)

writeln('El resultado es ', suma);

end.

En cada iteración del bucle, la variable de control indice toma distintos valores, empezando en
el valor que le demos a la variable primero y terminando en el valor de la variable segundo.
En cada una de las iteraciones vamos acumulando en la variable suma el valor previo más el
valor que toma la variable de control en dicha iteración. En la primera iteración, suma será
cero y la variable de control toma el valor de primero.

Si suponemos primero=3 y segundo=7

Número de Iteración Valor de indice Valor de suma Valor de segundo

Antes del bucle ?? 0 7

1 3 0+3=3 7

2 4 3+4=7 7

3 5 7+5=12 7

4 6 12+6=18 7

5 7 18+7=25 7

6 8 ¡Nos salimos del bucle! 7

Pero no tiene porqué creerse la tabla anterior. Quizás sea más interesante que lo
compruebe usted mismo. Para ello vamos a incorporar a nuestro programa lo que se
conoce como trazas de depuración, o de comprobación. Son sentencias de salida write
que muestran por pantalla por donde está fluyendo el código de nuestro programa.

En el caso de la suma, observe que hemos incorporado ahora dos sentencias writeln
antes y después del bucle, y dentro del bucle antes y después de la suma. Estas
sentencias nos muestran el valor de primero, segundo, indice y suma.

suma := 0; (* Hay que iniciar a cero antes de usar por primera vez su valor en
suma:=suma+indice*)
dep := true; (* ACTIVA/DESACTIVA true/false las trazas de
depuración *)
if (dep) then
writeln('** Antes del bucle: primero = ', primero, ' segundo = ', segundo, ' suma = ',
suma);
for indice:= primero to segundo do
begin
if (dep) then
writeln('** Iteracion ', indice, ' ANTES de sumar. Suma = ',
suma);
suma := suma + indice;
if (dep) then
writeln('** Iteracion ', indice, ' DESPUES de sumar. Suma = ',
suma);
end;
if (dep) then
writeln('** Despues del bucle: primero = ', primero, ' segundo = ', segundo, ' suma =
', suma);
writeln('La suma desde ', primero, ' hasta ', segundo, ' es ', suma);

Tras la ejecución de este nuevo código, el resultado será similar a:

Estas trazas son muy útiles a la hora de localizar errores en nuestros programas.
Normalmente, una vez comprobado el funcionamiento de estas trazas se eliminan del
código. En otras ocasiones, se incluyen estas trazas en una selectiva simple, controlada
por una variable de tipo lógico que el programador inicia a true o false.

dep := true; (* ACTIVA/DESACTIVA true/false las trazas de depuración *)

if (dep) then
writeln('** Antes del bucle: primero = ', primero, ' segundo = ', segundo, ' suma = ',
suma);

Estudie el código final de la suma en [Link]. Ejecútelo y pruebe a sumar entre distintas
parejas de valores.

A partir de ahora podrá (y deberá) usar estas trazas en sus ejercicios y ejemplos para
comprobar el correcto funcionamiento de sus programas.

Bucles DESDE anidados


No hay límite al número de bucles que se pueden anidar, siempre que estén totalmente
incluidos unos en otros.

Se pueden anidar dos bucles desde, y cada iteración del bucle externo provoca una
iteración completa del bucle interno.

Veamos como ejemplo de bucles anidados este programa que presenta por pantalla las
tablas de multiplicar.

(* Primera presentación, sin pausa.*)

for i:= 1 to 10 do

for j:=1 to 10 do

writeln( i,' x ', j, '= ', i*j);

No olvide antes de continuar estudiar el código de los ejemplos previos: Suma y


Multiplica.

Estudiaremos a continuación el bucle "mientras".

Program Sumar;
(*
Ejemplo del uso del bucle desde.

Suma los números comprendidos entre dos lÃmites que el usuario


introduce por pantalla. P.e.
a = 3
b = 6
=> suma = 3 + 4 + 5 + 6

*)

Var
primero: integer; (* Primer operando *)
segundo: integer; (* Segundo operando *)
suma: integer; (* Resultado *)
indice: integer; (* Var. de control del bucle desde *)
begin
writeln('Este programa suma los numeros entre dos valores');
writeln('Introduzca el primer operando: ');
readln(primero);
writeln('Introduzca el segundo operando: ');
readln(segundo);

suma := 0; (* Hay que iniciar a cero antes de usar por primera vez
su valor en suma:=suma+indice*)
for indice:= primero to segundo do
suma := suma + indice;

writeln('El resultado es ', suma);


end.

Program Multiplica;
(*
Ejemplo del uso del bucle desde anidado

Va presentando en pantalla las tablas de multiplicar del 1 al 10


Primero todas seguidas
Luego haciendo una pausa entre cada una
*)

Var
i, j: integer; (* Variables de control de los bucles desde *)
sigue: char; (* Var. auxiliar para facilitar la
presentación *)

begin

(* Primera presentación, sin pausa. *)


for i:= 1 to 10 do
for j:= 1 to 10 do
writeln( i,' x ', j, '= ', i*j);

(* Segunda presentación, con pausa. *)


for i:= 1 to 10 do
begin
for j:=1 to 10 do
writeln( i,' x ', j, ' = ', i*j);
write('Pulse RC');
readln(sigue);
end;
end.
Bucle Mientras

El funcionamiento de este bucle es el siguiente:

1. Se evalúa la condición.
2. Si la condición es falsa, no se ejecuta el bucle.
3. Si la condición es verdadera, se ejecuta el bucle y se vuelve al punto 1.

Esto queda reflejado en la siguiente figura:

En esta figura:

• En el símbolo inicial (rombo) se evalúa la condición del


bucle.
• Si la condición se cumple:
o Tomamos la rama positiva.
o Se ejecutan las acciones especificadas en el
bucle.
o Una vez ejecutas estas, el flujo del programa
regresa a evaluar la condición
• Si la condición no se cumple, termina la ejecución del
bucle, lo que se representa con el brazo etiquetado como
NO en la figura.

Dos comentarios antes de continuar:

• Puede ser que si la condición es falsa en su primera evaluación, las sentencias que
forman el bucle no se ejecute ninguna vez.
• Debe existir dentro del bucle algún mecanismo para modificar la condición que
controla el bucle y evitar un bucle infinito, donde la iteración se repite
indefinidamente porque no es posible modificar la condición de salida del bucle. En
este caso el programa no acabaría nunca.

Es Pascal, la sentencia que representa este comportamiento es:

while (condicion) do
sentencia_a;

No olvidemos que la sentencia que se repite puede ser una sentencia compuesta, con
su correspondientes begin-end

while (condicion) do
begin
sentencia_a_1;
sentencia_a_2;
sentencia_a_3;
end;

O sangrando con otro estilo:

while (condicion) do begin


sentencia_a_1;
sentencia_a_2;
sentencia_a_3;
end;

Como ejemplo del uso de este bucle, se calcula el factorial de un número entero
positivo. El factorial de un número entero positivo es el resultado de multiplicarlo por
todos los que le preceden hasta llegar a 1. A esta operador se le asigna el símbolo de
exclamación.

Por lo tanto:
el factorial de 2 ( 2! ) es 2*1
el factorial de 3 ( 3! ) es 3*2*1
el factorial de 4 ( 4! ) es 4*3*2*1,

Observe el fragmento de código, y la tabla que le acompaña donde se muestran


los valores de las distintas variables en las iteraciones del bucle. A la variable
factorial, que acumula el producto, se le da un valor inicial de 1.

Sección de código del programa Factorial

factorial := 1;
cantidad := 7;
while (cantidad > 0) do
begin
factorial := factorial * cantidad;
cantidad := cantidad -1;
end;
Factorial de 7
Número de Iteración Valor de cantidad Valor de factorial

Antes del bucle 7 1

1 7 1*7 = 7

2 6 7*6 = 42

3 5 42*5 = 210

4 4 210*4 = 840

5 3 840*3 = 2520

6 2 2520*2 = 5040

7 1 5040*1 = 5040 = 7*6*5*4*3*2*1

8 0 ¡¡ No entramos en el bucle !!

Repase el código de este ejemplo en Factorial.

Sólo nos queda una estructura repetitiva por estudiar: el bucle "repetir-hasta".
Program Factor;
(*
Uso de bucle mientras

Calcula el factorial de un número positivo entero.

Para compronder el funcionamiento del factorial consulte la guía de


curso

*)

Var
cantidad: integer; (*
Factorial que deseamos calcular *)
factorial: integer; (*
Resultdo *)

begin
writeln('Calculo del factorial de un numero entero ');
write('Introduzca el numero: ');
readln(cantidad);

factorial := 1; (* Se inicia a uno porque


acumula un producto *)
while (cantidad > 0) do
begin
factorial := factorial * cantidad;
cantidad := cantidad -1;
end;
writeln('el resultado es ', factorial);
end.
Bucle Repetir-Hasta

El funcionamiento de este bucle es el siguiente:

1. Se ejecutan las sentencias que forman parte del bucle.


2. Se evalúa la condición
3. Si es falsa, ir a 1.
4. Si es verdadera, termina la ejecución del bucle.

En esta figura:

• Se ha representado con un pequeño círculo el lugar


donde se reunen las flechas de flujo del programa. En ese
lugar no hay sentencias de ningún tipo.
• En esta estructura, cuando se cumple la condición se
acaba el bucle, al contrario que en el bucle mientras.
• Si la condición no se cumple, regresamos a ese círculo
previo al conjunto de sentencias del bucle.

Las diferencias con la estructura MIENTRAS son dos:

• Esta estructura siempre se ejecuta al menos una vez.


• El bucle se repite hasta que la condición de control se hace verdadera.

En Pascal esta estructura se corresponde con la sentencia repeat-until:

repeat
sentencia_a;
until (condicion);
En este caso, si la sentencia es compuesta, no son necesarios los identificadores begin-
end, ya que los identificadores repeat y until hacen de delimitadores de bloque.

Este tipo de bucles es muy adecuado para situaciones en las que a priori conozcamos
que hay que ejecutar el bucle al menos una vez. Este es el caso de programas que
solicitan al usuario opciones por pantalla, que posteriormente hay que comprobar que
son correctas.

Vea como ejemplo otra versión de la calculadora básica ya estudiada:

Sección de código del programa Calc1

repeat

write('Introduzca el primer operando: ');


readln(a);
write('Introduzca el segundo operando: ');
readln(b);
writeln(' Opciones: S(sumar), R(restar), M(multiplicar), D(dividir)');
readln(opcion);
case (opcion) of

'S','s' : res:= a+b;


'R','r' : res:= a-b;
'M','m' : res:= a*b;
'D','d' : res:= a/b;

end;
writeln(' El resultado es ', res);
write(' Terminar (S/N)?: ');
readln(opcion);

until ((opcion ='S') or (opcion ='s')) ;

Observe el bucle repeat-until y dentro de este la selectiva múltiple. Ejecute el código


para ver su comportamiento completo.

Program Calc1;
(*
Ejemplo del uso del bucle REPETIR-HASTA

Versión modificada de [Link] para poder repetir


operaciones.

*)

Var
opcion: char; (* Para comprobar si desea continuar el
usuario *)
a: real; (* Primer
operando *)
b: real; (* Segundo
operadno *)
res: real; (* REsultado final *)

begin
writeln('Calculadora basica');

repeat
write('Introduzca el primer operando: ');
readln(a);

write('Introduzca el segundo operando: ');


readln(b);

writeln(' Opciones: S(sumar), R(restar),


M(multiplicar), D(dividir)');
readln(opcion);

case (opcion) of
'S','s' : res:= a+b;
'R','r' : res:= a-b;
'M','m' : res:= a*b;
'D','d' : res:= a/b;
end;

writeln(' El resultado es ', res);

write(' Terminar (S/N)?: ');


readln(opcion);

until ((opcion ='S') or (opcion ='s')) ;


end.

Es posible que en otros lenguajes en vez de la estructura repetir-hasta tenga disponible


la estructura repetir-mientras. La única diferencia que la ejecución se mantiene hasta
que la condición sea verdadera o hasta que se haga falsa.

Vistas las estructuras de control básicas y una vez que haya repasado los ejemplos de
este tema, pase al siguiente tema: subprogramas o módulos.
Introducción

Se ha establecido en temas anteriores que la programación modular es necesaria para


realizar programas correctos. Para facilitar esta tarea los lenguajes de programación
proporcionan lo que se conoce como módulos, subrutinas o subprogramas.

Un subprograma o módulo es un conjunto de instrucciones que realizan una


determinada tarea. Es posible hacer que ese módulo se ejecute tantas veces como se
desee. También es posible que desde un módulo se llame o invoque a otro módulo.

Los módulos se utilizan para:

• Dividir un determinado problema en partes, agrupando cada una de estas partes en un


módulo.
• Programar tareas que se repiten varias veces a lo largo del programa, de forma que se
codifican una única vez.
• Parametrizar una determinada tarea: permitir que un subprograma sea capaz de
realizar una misma tarea con distintos datos de entrada.

Todo programa en Pascal (y en general en cualquier lenguaje de programación de alto nivel)


tendrá un módulo llamado principal.

Este módulo hace las veces de director de orquesta: el programa empieza en la primera
sentencia de este módulo y termina con la última sentencia de este. Si el problema a
resolver es muy simple todo el programa se codifica en dicho módulo. Si es más
complejo, serán necesarios otros módulos, y el módulo principal será el encargado de
llamarlos.

En Pascal el módulo principal es el cuerpo begin-end. del programa. Si existen otros


módulos, estos se definen antes del cuerpo del programa principal, como vimos al
estudiar la estructura de un programa en Pascal.

program nombre_del_programa ;

uses
unidades;
const
const_1 = valor_1;
const_2 = valor_2;
type
tipos_definidos_por_el_usuario;
var
declaración_de_variables;

{** Funciones y procedimientos **}


procedure
definiciones_de_procedimientos;
function
definiciones_de_funciones;
{** Cuerpo del programa **}
begin
sentencias;
end.
Conexiones entre subprogramas. Transferencia de parámetros

Si se descompone un programa en partes o módulos será necesario que se comuniquen


de alguna forma para que los resultados de un módulo sean utilizados por otro. Es
necesario que los subprogramas se transmitan información.

Suponga que desea codificar un módulo que calcule el precio de venta al público (PVP)
de un producto: esté deberá recibir de alguna forma el precio de ese producto y el IVA
que se le aplica. Si el módulo se llama calcula_PVP, se espera un funcionamiento
similar a:

Módulo calcula_PVP: muestre por pantalla el precio final de un libro de valor 1000 pesetas, al
que se le aplica un 7% de IVA.

Se le proporciona información al módulo para que realice su tarea: el valor del libro y el
IVA que se le aplica. Se dice que el valor del libro y el IVA son parámetros del
subprograma. Esto significa que este módulo o subprograma se puede utilizar para
productos de distinto precio y con distinto valor de IVA.

Al mismo tiempo el módulo me devuelve información: el precio final del libro. Esta
información se puede devolver de distintas formas:

• Como parámetro.
• Como resultado del módulo.
• Por algún periférico de salida, por ejemplo la pantalla. De esta forma el programa no
puede seguir usando el resultado para otros cálculos.

Utilicemos el ejemplo del PVP de un producto para estudiar como se definen y utilizan los
módulos en Pascal:

Definición de una función

Una función se define (y veremos que un procedimiento se define de forma similar) siguiendo
un esquema similar al de un programa. Estudiemos la función PVP y desglosemos sus partes:

Function PVP(valorprod: real; ivaprod: real): real;


var
total_iva : real;
begin
total_iva := valorprod*ivaprod/100;
PVP := valorprod + total_iva;
end;

Esta función la puede encontrar en [Link].

• En la primera línea se define el nombre de la función (PVP), los parámetros (valor e iva
y sus tipos) y finalmente el tipo de datos del valor que devuelve la función (real).
• A continuación las secciones de constantes (const), tipos (type) y variables (var). En
este ejemplo sólo aparece la sección de variables.
Estas variables definidas dentro de una función son las que denominábamos locales.
• Finalmente, el cuerpo de la función, encerrado entre un par begin-end;. La sentencia
end final está terminada en ";" y no en un "." como en el cuerpo del programa
principal.
• La última línea de la función es una sentencia de asignación que le da valor a una
variable, que debe tener el mismo nombre que la función. De esta forma la función
devuelve un valor como resultado de su ejecución. Esta línea debe ser siempre la
última.

Llamada o invocación de una función

Para que dicha función se ejecute simplemente hay que "invocarla" o llamarla desde otro
módulo, escribiendo su nombre y colocando entre paréntesis los valores que queremos que
reciba la función para trabajar. Como la función devuelve un valor, es necesario que se le
asigne dicho valor devuelto a una variable, o que se utilice dentro de una expresión:

total := PVP(1700, 10);


Recuerde que en una sentencia de asignación primero se ejecuta la parte derecha del
operador ":= ". En este caso estamos invocando o llamando a la función PVP, y
proporcionándole como información que el valor del producto es 1700 pesetas y el IVA es del
10 %, y esperamos que nos devuelva como resultado el PVP. Una vez que se ha ejecutado la
función PVP, nos devuelve el valor 1870, que se lo asignamos a la variable total.

En esta llamada hemos usado constantes (1700 y 10), pero se pueden usar en la
invocación a la función variables, a las que previamente se les ha asignado un valor:

valor_libro := 1500;
iva_libro := 7;
total := PVP(valor_libro ,iva_libro);
o la invocación puede ser parte de expresiones más complejas:

total := numero_articulos * PVP(valor_libro ,iva_libro);

Parámetros reales y formales

Hemos introducido el concepto de parámetro. Debemos distinguir entre los parámetros


que aparecen en la definición de la función y los parámetros que aparecen en la llamada
a la función:

• Los parámetros reales son los que se utilizan (ya sean expresiones o variables) cuando
se invoca a un módulo. En los ejemplos previos, 1500 y 7, o valor_libro e iva_libro son
parámetros reales.
• Los parámetros formales son los que se usan en la definición de un módulo. En el
ejemplo del PVP, parámetros formales son valor e iva. Dentro de la función, los
parámetros formales se tratan como variables locales de la función.

Correspondencia de parámetros

Podemos observar que la función tiene parámetros formales únicos, pero que cada vez que
llamamos o invocamos a la función los parámetros reales pueden ser distintos.
La correspondencia entre parámetros reales y formales se realiza de la siguiente forma:

• Cuando se invoca un módulo, se establece una correspondencia entre los parámetros


reales y los parámetros formales.
• Esta correspondencia se va a efectuar según el orden en que aparezcan en la sentencia
de llamada, y según el orden en que fueron declaradas (correspondencia posicional).
• Por lo tanto, el número de parámetros reales ha de coincidir con los parámetros
formales, y además han de ser del mismo tipo.
• Finalmente, esta correspondencia podrá ser de dos tipos, por valor o por referencia.
Estudiaremos estos tipos en apartados posteriores.

Ejemplo Transferencia de parámetros

Hemos visto qué son los parámetros, cómo se definen las funciones, qué son parámetros
formales y reales, y como se corresponden los parámetros al hacer la llamada a la
función.

Pero antes de continuar con este tema, vamos a intentar entender, mediante trazas, como
se produce la transferencia de parámetros. Para ello vamos a situar trazas en nuestro
programa PVP antes de la llamada a la función, y dentro de la propia función.

... Function PVP(valorprod: real; ivaprod: real): real;


var

total_iva : real;

begin

if (dep) then
begin

writeln('%%%%% Dentro funcion PVP');


writeln('%%%%% Antes de ninguna sentencia. valorprod: ',
valorpro[Link], ' ivaprod: ', ivapro[Link]);

end;

total_iva := valorprod*ivaprod/100;
PVP := valorprod + total_iva;
end;

(** Cuerpo del programa principal **)

begin

total := 0;
dep := true; (* ACTIVA/DESACTIVA las trazas de depuración *)
write('Introduzca el valor del producto: ');
readln(valor);
write('Introduzca el IVA del producto: ');
readln(iva);
writeln;

if (dep) then

writeln('** Antes funcion PVP. Valor: ',


valor:0:1, ' IVA: ', iv[Link], ' total: ', total:0:1);

if (dep) then

writeln('** sentencia que se va a ejecutar: total = PVP(valor,iva)');

total := PVP(valor,iva);

if (dep) then

writeln('** Despues funcion PVP. Valor: ',


valor:0:1, ' IVA: ', iv[Link], ' total: ', total:0:1);

writeln;
writeln('El precio final es: ', total:0:1);
writeln;

(* *********************** *)

if (dep) then

writeln('** sentencia que se va a ejecutar: total = PVP(3000,20)');

total := PVP(3000,20);
writeln;
writeln('El precio final es: ', total:0:1);
writeln;

(* *********************** *)

if (dep) then
writeln('** Antes funcion PVP. Valor: ',
valor:0:1, ' IVA: ', iv[Link], ' total: ', total:0:1);

if (dep) then

writeln('** sentencia que se va a ejecutar: total = PVP(valor*10, 20-2)');

total := PVP(valor*10,20-2);
writeln;
writeln('El precio final es: ', total:0:1);

end.

Las trazas de depuración están destacadas en color rojo: antes de las llamadas a la función
PVP, y dentro de esta función.

En especial, observe la traza dentro de la función. Está justo al comienzo de dicha


función. Cuando se ejecute dicha sentencia no se ha ejecutado ninguna línea de código
de la función.

Function PVP(valorprod: real; ivaprod: real): real;


var
total_iva : real;
begin
if (dep) then
begin
writeln('%%%%% Dentro funcion PVP');
writeln('%%%%% Antes de ninguna sentencia. valorprod: ',
valorpro[Link], ' ivaprod: ', ivapro[Link]);
end;

total_iva := valorprod*ivaprod/100;
PVP := valorprod + total_iva;
end;

Observe que dicha traza intenta presentar por pantalla los valores almacenados en los
parámetros formales valorprod e ivaprod. El código completo lo puede encontrar en
[Link].

Tras compilarlo y ejecutar nos queda:


Observe las tres llamadas a la función PVP que hay en el programa principal:

• total := PVP(valor,iva);
Los parámetros reales son dos variables, valor e iva. El primero, valor, se corresponde
con el parámetro formal valorprod, y el segundo, iva, con ivaprod.

valor se copia en valorprod


iva se copia en ivaprod

Dentro de la función, estos parámetros toman los valores de los parámetros


reales sin que exista ninguna sentencia de asignación. No es magia: se ha
realizado de forma automática la correspondencia de parámetros entre reales y
formales.

• total := PVP(3000,20);
En esta los parámetros reales son constantes. Observe en el gráfico resultado de la
ejecución la correspondencia.
• total := PVP(valor*10,20-2);
En esta los parámetros reales son expresiones: la variable valor*10, e iva-2. Observe
en la figura que valores toman los parámetros formales dentro de la función: 1000 y
18.
Tipos de correspondencia de los parámetros

Los parámetros se pueden corresponder según dos criterios:

• por valor: cuando se pasa un parámetro por valor, en el momento de la llamada a la


función se copia el valor del parámetro real en el parámetro formal. Si modificamos el
parámetro formal dentro de la función NO se modifica el parámetro real:

P. REAL se copia en P. FORMAL

En Pascal, por defecto, los parámetros se pasan por valor. En el ejemplo previo, los dos
parámetros formales son por valor. Hasta este momento todos los parámetros
definidos son por valor.

• por referencia: Cuando se pasa un parámetro por referencia, se considera que el


parámetro real y el formal son la misma variable, y cualquier modificación en la
función sobre el parámetro formal implica que estamos modificando el parámetro
real.

P. REAL es equivalente a P. FORMAL

Para especificar en Pascal un parámetro por referencia se utiliza la palabra reservada


VAR antes de la definición del parámetro formal, como se hace en el siguiente
ejemplo:

Procedure Swap(VAR x, y: Integer);

Como puede observar, ya no es una función sino un procedimiento. Y eso es lo que


vamos a estudiar a continuación. Veremos ejemplos del uso de parámetros por
referencia en los ejemplos de este tema, y sobre todo en el tema de tablas.

Procedimientos

Hemos estudiado que una función devuelve un valor como resultado de la función. Un
procedimiento es simplemente un módulo o subprograma que no devuelve nada como
resultado de su ejecución.

Esta distinción no es del todo exacta: Un procedimiento no devuelve información como


resultado de su ejecución, pero si puede devolver información a la función que lo ha
llamado mediante parámetros por referencia.

Definición de un procedimiento

Un procedimiento se define:

Procedure Suma (Real:a,b);


var
total: real;
begin
total := a + b;
write( a, ' + ', b, ' = ', total);
end;
Como podemos comprobar, es muy similar a la definición de una función: cambia la palabra
reservada function por procedure y no devuelve nada como resultado de la función. Esto
implica que no es necesaria una sentencia de asignación con el nombre de la función al final
del procedimiento.

Invocación de un procedimiento

La llamada a un procedimiento es similar a la de una función; se especifica su nombre y los


parámetros reales:

nombre_del_procedimiento (parametros_reales_sin_tipo);

Pero en el caso de procedimientos, estos no pueden ser parte de expresiones como las
funciones, ya que no devuelven ningún valor como resultado.

La invocación del procedimiento suma podría ser:

suma (7,5);
pero nunca
total := suma (7,5);(* Incorrecto *)

Observe este ejemplo: además del procedimiento suma se ha codificado un


procedimiento sin parámetros que hace una presentación inicial por pantalla. Descubra
como se define e invoca dicho procedimiento sin parámetros.

Intentemos ahora mediante ejemplos ver la diferencia entre parámetros por valor y
referencia, y entre funciones y procedimientos.
Ejemplos Prácticos

Quizás la parte más difícil de la programación sea, ante la resolución de un determinado


problema, decidir como se descompone en funciones o procedimientos.

La primera aproximación es separar tres grandes bloques: entrada de datos, cálculo de


resultados y presentación final de los resultados.

Seguir desglosando estos bloques en módulos depende de la complejidad del problema.


Al mismo tiempo el decidir si un módulo será función o procedimiento dependerá del
algoritmo particular que vayamos a implementar.

Ejemplo 1: Suma de dos elementos

Queremos implementar un modulo que reciba dos parámetros y devuelve la suma de los
dos primeros. Previamente hemos visto un procedimiento que sumaba dos elementos, y
presentaba el resultado por pantalla.

Lo que deseamos es modificar dicho ejemplo para que devuelva como resultado del
módulo la suma.

Intente modificarlo usted mismo antes de ver la solución, que le explicamos a


continuación:

• Al iniciar la ejecución se definen las variables a, b y total, y se procede a solicitar al usuario


los valores de a y b.

• A continuación se llama a la función:

total := suma(a, b); a y b son los parámetros reales.

• Dentro de la función:

• Se realiza la correspondencia: los parámetros reales se corresponden con los parámetros


formales.

• Observe: los parámetros formales tienen el mismo identificador que los reales. Pero no son
los mismos: los parámetros formales sólo existen dentro de la función, y se consideran locales
a la función.
• a := a+b;
Se suman a y b, y el resultado se almacena en el parámetro formal a .

• suma := a;
El valor de la suma, almacenado en a, se devuelve como resultado de la función.

• Al acabar la ejecución de la función, el resultado de la función se asigna a total.

• Se presenta total por pantalla.

Gráficamente:

Insistimos en un par de puntos:

• Las variables a y b del programa principal, globales, tienen los mismos identificadores que
los parámetros formales a y b de la función suma.
Sabemos que los parámetros formales se consideran locales a la función. Cuando variables
locales y globales coinciden en el identificador las referencias válidas son las de las variables
más "internas". Por lo tanto "predominan" los parámetros formales y las variables locales
sobre las variables globales.

• Si deseamos usar una variable global dentro de una función o procedimiento que tiene una
variable de tipo local (o un parámetro) con el mismo identificador tendremos que cambiar
alguno de los dos.

• Por otra parte, hemos modificado el parámetro formal a dentro de la función suma, pero
esto no significa que se haya modificado el parámetro real a, ya que lo hemos pasado por
valor. Para comprobar este último punto puede utilizar trazas de depuración para presentar el
valor de las variables globales a y b después de la llamada a la función.

Modifique el programa para que la salida tras ejecutarse sea similar a la siguiente:
Ejemplo 2: Intercambio

En el ejemplo anterior hemos comprobado que al pasar un parámetro por valor a una función,
es imposible modificar el parámetro real dentro de la función: se transfiere una copia.

Veamos a continuación como es necesario pasar los parámetros por referencia para
poder modificarlos dentro de una función o procedimiento.

El siguiente programa intercambia el valor de dos variables: es necesario modificarlas


dentro del módulo. Para ello el modulo debe definir los parámetros formales por
referencia (VAR). Vamos a analizar el algoritmo de [Link]

• Al iniciar el programa se le da valor a las variables a y b.

• Después se llama a la función swap (intercambio en inglés), pasando como parámetros


reales por referencia las variables a y b.

• La función recibe las referencias a ambas variables y se las asigna a los parámetros formales
x e y.
• A continuación intercambia el contenido de ambas variables. Para ello necesitamos una
variable auxiliar, aux, y realizar las sentencias de asignación en el orden que se indica la
siguiente figura:

• Una vez realizado el intercambio, se devuelve el control al programa principal, que es el que
ha llamado al procedimiento. No olvidemos que como el paso de parámetros es por referencia
realmente hemos intercambiado las variables a y b.

Para comprobar todo esto, nada mejor nuevamente que utilizar trazas de depuración. Observe
el resultado: dentro de la función swap se modifican las variables globales x e y.

El código de la función swap queda:


Procedure Swap(VAR x, y: Integer);
Var

aux : Integer;

Begin

if (dep) then

begin

writeln('%%%% Entrando en funcion swap: a: ', a, ' b: ', b);


writeln('%%%% Entrando en funcion swap: x: ', x, ' y: ', y);

end;
aux := y; (* almacena en aux el valor de y para que no se pierda en *) (* la siguiente
asignación *)
y := x;
x := aux; (* Le asigna el valor de y que se guardo en aux *)

if (dep) then
begin

writeln('%%%% Saliendo de funcion swap: a: ', a, ' b: ', b);


writeln('%%%% Saliendo de funcion swap: x: ', x, ' y: ', y);

end;

End;

y el código completo lo puede encontrar en intercambio_dep.

No olvide revisar el código de los ejemplos antes de pasar al tema siguiente, e intentar
realizar los ejercicios propuestos.
(*

Tema 6: Subprogramas

Programa ejemplo del uso de parámetros por referencia.


Intercambia el valor de dos variables.
Con trazas de depuracion

*)

Program Intercambio;
Var
a: integer;
b: integer;
dep: boolean; (*Controla depuración *)

(* Procedimiento que intercambia el valor de dos variables *)


(* Para ello es necesario pasar las dos variables por valor *)
Procedure Swap(VAR x, y: Integer);
Var
aux : Integer;
Begin
if (dep) then
begin
writeln('%%%% Entrando en funcion swap: a: ', a, '
b: ', b);
writeln('%%%% Entrando en funcion swap: x: ', x, '
y: ', y);
end;

aux := y; (* almacena en aux el valor de y para que no se


pierda en *)
(* la siguiente asignación
*)
y := x;
x := aux; (* Le asigna el valor de y que se guardo en aux
*)

if (dep) then
begin
writeln('%%%% Saliendo de funcion swap: a: ', a, '
b: ', b);
writeln('%%%% Saliendo de funcion swap: x: ', x, '
y: ', y);
end;

End;

(* Modulo principal *)
begin
dep := true; (* ACTIVA/DESACTIVA las trazas de
depuración *)

(* Valores iniciales: se piden al


usuario *)
write('Introduzca primer operando : ');
readln(a);
write('Introduzca segundo sumando : ');
readln(b);
writeln;
writeln('Antes de intercambio: a= ', a, ' b= ', b);
writeln;

Swap(a, b);

writeln;
writeln('Despues de intercambio: a= ', a, ' b= ', b);
writeln;

end.
Introducción

Podríamos hacer una primera clasificación de los tipos de datos que maneja un
ordenador: tipos de datos simples y tipos de datos compuestos.

• Simples: son aquellos que sirven para representar información de tipos


elementales como por ejemplo números enteros, reales o información de tipo
carácter. Son los que hemos estudiado hasta este momento.
• Compuestos: son conjuntos de datos simples relacionados entre sí de alguna
forma.

Dentro de los tipos de datos compuestos, podremos hablar de estáticos y de dinámicos.


En los primeros el tamaño de los datos está prefijado al iniciar el programa. En los
segundos el tamaño de los datos puede variar durante la ejecución del programa.

Definición

En este apartado vamos a introducir una estructura compuesta: las tablas, y en concreto
las de carácter monodimensional (una dimensión). Más adelante estudiaremos las tablas
multidimensionales (más de una dimensión).
Definimos tabla como un conjunto finito y ordenado de elementos homogéneos. Las
tablas también reciben el nombre de matrices o arrays.

• Finito: está compuesta por un número limitado de elementos.


• Ordenado: los elementos se pueden referenciar según su posición (su
orden en la tabla).
• Homogéneos: los componentes de una tabla han de ser del mismo tipo.

En las tablas monodimensionales los elementos están ordenados desde el primero hasta
el último, pudiendo acceder a los mismos mediante un índice que indica su posición.

Una tabla se identifica por un nombre. Si especificamos dicho nombre sin hacer
referencia al índice nos estaremos refiriendo a la tabla entera, no a alguno de sus
elementos.

Para acceder al contenido de un elemento de una tabla se deberá especificar el nombre


de la tabla e indicar mediante un índice la posición del elemento en cuestión.
El índice de una tabla podrá variar desde el límite inferior hasta el superior, que se
especifican en la definición de la tabla. Estos límites deberán ser constantes, y por lo
tanto el tamaño de la tabla esta fijado en el momento de la compilación.

Las tablas se utilizan para facilitar el acceso a información que puede ser agrupada
siguiendo algún concepto lógico de agrupación, y que además sea información
homogénea, por ejemplo:

• Las notas de un conjunto de alumnos: todas son del mismo tipo, reales, y
podemos tener a los alumnos ordenados alfabéticamente.
• Los precios de los productos de una tienda: son todos del mismo tipo, y pueden
ser ordenados por el número de referencia.
• Las medidas de un termómetro, o cualquier tipo de sensor o alarma, a lo largo
del día: todas las medidas serán del mismo tipo, y pueden ser ordenadas por la
hora en que fueron tomadas.

Puede encontrar la representación gráfica de una tabla de la siguiente forma:

Pasemos a estudiar como se definen y usan las tablas en Pascal.


Definición

Para definir una tabla en Pascal se utiliza la palabra reservada array. Además necesitamos
conocer:

• El tamaño de la tabla, indicando su índice inicial y final.


• El tipo de los elementos de la tabla o tipo base.

Se pueden definir directamente variables de tipo tabla o utilizar la sección de tipos definidos
por el usuario:

Type
lecturas = array[1..24] of integer; (* tipo base: integer *)

Var
temperaturas : lecturas; (* Almacena temperaturas cada hora *)
humedad : lecturas; (* Almacena humedad cada hora *)
medias: array[1..31] of real;
i: integer;

Definimos en la sección Type un tipo definido por el usuario de nombre lecturas, que será una
tabla de 24 valores de tipo entero. Una vez definido este tipo lecturas, podremos usarlo en las
definiciones de variables como cualquier tipo básico. Es lo que encontramos a continuación: la
definición de dos variables, temperatura y humedad de ese tipo.

En la misma sección definimos otra tabla de nombre medias, que almacena 31 valores
de tipo real. Observe la notación para especificar el valor inicial y final de los índices,
encerrados entre corchetes y separados por dos puntos.

Utilización

Para acceder a un elemento de la tabla simplemente necesitamos el nombre de la tabla y el


índice de ese elemento. A partir de ese momento lo podremos usar en cualquier expresión tal
como usábamos las variables de tipos simples, variables de tipo entero o real:

temperaturas[7] := 25;
media := (temperaturas[7] + temperaturas[8]) / 2;
O en operaciones de lectura y escritura:

write('Introduzca la temperatura al mediodia');


readln( temperaturas[12] );
write( 'La temperatura a las 12:00 es de ', temperatura[12] );

Tablas y bucles

Lo que hace realmente útil y potente a las tablas es la posibilidad de usarlas en bucles, en los
que la variable de control se utiliza al mismo tiempo como índice de acceso a los elementos
de la tabla:
writeln('Introduzca los valores de las temperaturas(01:00 hasta 24:00')
for i:= 1 to 24 do
begin

write('Temp. a las ', i, ': ');


readln(temperatura[i]);

end;

En este bucle se solicita al usuario que vaya introduciendo las temperaturas medidas a lo largo
del día. Y para ello aprovecha la variable de control (o índice) para acceder a los distintos
elementos de la tabla temperatura.

Tablas y módulos

Los módulos (funciones y procedimientos) pueden recibir como parámetros tablas. Siguiendo
los ejemplos anteriores, observe esta función que recibe como parámetro una tabla (del tipo
lecturas) y devuelve como resultado de la función la media de las medidas realizadas.

Para calcular la media de un conjunto de valores se suman todos los valores, y la suma total se
divide por el número de valores. Para ello necesitamos una variable que acumule la suma, e
iniciarla antes del bucle a cero.

Function Media(medidas: lecturas): Real;


Var
i: integer;
suma: integer;
Begin
suma := 0;
for i:= 1 to 24 do
suma:= suma + medidas[i];
Media := suma/24.0
End;

No es posible en Pascal que una función devuelva como resultado de la función una tabla. Por
lo tanto la única manera de modificar una tabla dentro de una función o procedimiento es
pasarla por referencia. Puede repasar como se usan los parámetros por referencia o consultar
el tema de subprogramas.

Observe la siguinte función Lectura: se solicita al usuario que vaya tecleando los 24
valores de temperatura y se van almacenando en los elementos de la tabla, que se ha
pasado por referencia. Y de nuevo utilizamos la variable de control del bucle como
índice de los elementos de la tabla.

Procedure Lectura(VAR medidas: lecturas);


Var
i: integer;
Begin
writeln('Introduzca los valores(01:00 hasta 24:00');
for i:= 1 to 24 do
begin
write('Medida a las ', i, ': ');
readln(medidas[i]);
end;
End;

Existe otra limitación: es necesario definir un tipo de datos definido por usuario
(sección Type) que se corresponda con la tabla antes de definir la función y usarla como
parámetro. La siguiente definición sería errónea:

(* *)
(* !!!!!!!!!!!! Este procedimiento no compila !!!!!!!!!!!!!!! *)
(* *)
Procedure Lectura(VAR medidas: array[1..24] of integer);
Var
i: integer;
Begin
writeln('Introduzca los valores(01:00 hasta 24:00');
for i:= 1 to 24 do
begin
write('Medida a las ', i, ': ');
readln(medidas[i]);
end;
End;

Será necesario definir primero un tipo de datos que se corresponda con esa tabla y usar el
identificador de ese tipo creado por el usuario en el procedimiento:

Type
lecturas = array[1..24] of integer;

Procedure Lectura(VAR medidas: lecturas);


Var
i: integer;
Begin
writeln('Introduzca los valores(01:00 hasta 24:00');
for i:= 1 to 24 do
begin
write('Medida a las ', i, ': ');
readln(medidas[i]);
end;
End;

Antes de continuar, estudiemos ejemplos de uso de tablas y funciones. Vamos a analizar


una función que calcula la media de todos los valores de una tabla.

Function Maximo(medidas: lecturas): Integer;


Var
i: integer;
max: integer;
Begin
(* Como no conocemos los valores de la tabla *)
(* suponemos que el primer valor es el max. *)
max := medidas[1];
(* Recorremos el resto de la tabla comprobando
*)
for i:= 2 to 24 do (* si hay algún valor mayor en la tabla
*)
if max < medidas[i] then
max := medidas[i]; (* si lo hay, es nuestro nuevo máximo
*)

Maximo := max;
End;

• La tabla medidas se pasa por valor: no hay que modificarla, sólo consultarla.
• Se supone que el máximo es el primero elemento de la tabla.
• A continuación se recorre el resto de la tabla. En el caso que algún valor sea mayor que
le primero, será nuestro nuevo máximo.
• La última sentencia de la función es una sentencia de asignación. Recuerde: se le
asigna al nombre de la función el valor que deseamos que devuelva la función.

Repase todas estas funciones, y algunas más, en el programa [Link]. Observe que si
compila este ejemplo recibirá unos mensajes de aviso o atención, llamados warnings o avisos
que puede observar en la siguinte figura:

Nos avisa que hemos definido variables que luego no se utilizan en el código. Esto es
debido a que dentro de este programa hemos conservado la versión inicial para que
compare como se va mejorando y haciendo modular un programa.
(*

Tema 7: Tablas

Se utilizan funciones que reciben tablas por valor o por referencia.


Se llama desde funciones a otras funciones.
Hay funciones de E/S.
Hay funciones de tipo "matemáticos".

*)

Program Tablas;

Type
lecturas = array[1..24] of integer;
(* Definimos un tipo de
tabla de 24 enteros *)

Var
temperatura : lecturas; (* Almacena temperaturas cada hora *)
humedad : lecturas; (* Almacena humedad cada hora *)

medias: array[1..31] of real;


i: integer;

(* Funciones matemáticas: Media, Maximo y Minimo *)


Function Media(medidas: lecturas): Real;
Var
i: integer;
suma: integer;
Begin
suma := 0;

for i:= 1 to 24 do (* Se recorre la tabla sumando su


elementos *)
suma:= suma + medidas[i];

Media := suma/24.0 (* Se divide por el número de elementos


*)
End;

Function Maximo(medidas: lecturas): Integer;


Var
i: integer;
max: integer;
Begin
(* Como no conocemos los valores de la tabla *)
(* suponemos que el primer valor es el max. *)
max := medidas[1];

(* Recorremos el resto de la tabla comprobando


*)
for i:= 2 to 24 do (* si hay algún
valor mayor en la tabla *)
if max < medidas[i] then
max := medidas[i]; (* si lo hay, es
nuestro nuevo máximo *)

Maximo := max;
End;
Function Minimo(medidas: lecturas): Integer;
Var
i: integer;
min: integer;
Begin
(* Como no conocemos los valores de la tabla *)
(* suponemos que el primer valor es el mínimo. *)
min := medidas[1];

(* Recorremos el resto de la tabla comprobando


*)
for i:= 2 to 24 do (* si hay algún valor menor en la
tabla *)
if min > medidas[i] then
min := medidas[i]; (* si lo hay, es
nuestro nuevo mínimo *)

Minimo := min;
End;

(* Funciones de lectura y presentación de resultados *)

(* Es necesario pasar medidas por referencia: va a ser modificada *)


Procedure Lectura(VAR medidas: lecturas);
Var
i: integer;
Begin
writeln('Introduzca los valores(01:00 hasta 24:00');

for i:= 1 to 24 do
begin
write('Medida a las ', i, ': ');
readln(medidas[i]);
end;
End;

(*
Este procedimiento no compila: no se puede definir uan tabla como
parámetro
de una función: hay que definierla previamente.
Por eso esta comentada !!!!!!!!!!!!!!!!!!!!!!!
*)
(*
Procedure Lectura_mod(VAR medidas: array[1..24] of integer);
Var
i: integer;
Begin
writeln('Introduzca los valores(01:00 hasta 24:00');
for i:= 1 to 24 do
begin
write('Medida a las ', i, ': ');
readln(medidas[i]);
end;
End;
*)

(* Funciones de presentación de resultados *)


Procedure Resultados_humedad( medidas: lecturas);
Begin
writeln('Humedad media: ', Media(medidas):0:1);
writeln('Humedad Max: ', Maximo(medidas));
writeln('Humedad Min: ', Minimo(medidas));
End;

(* Para hacer una función resultados genérica se le pasa el string


tipo. De
esta forma se puede utilizar para temperaturas o humedad
*)
Procedure Resultados( medidas: lecturas; tipo: string[15]);
Begin
writeln(tipo,' media: ', Media(medidas):0:1);
writeln(tipo,' Max: ', Maximo(medidas));
writeln(tipo,' Min: ', Minimo(medidas));
End;

(* Procedimiento sin parámetros: para "embellecer" *)

Procedure Presenta;
Begin

writeln('*********************************************************');
writeln('*
*');
writeln('*
*');
writeln('*
*');
End;

(* Modulo principal *)
begin

lectura(humedad);
resultados(humedad, 'Humedad');

(* La función resultados se encarga de invocar

las funciones máximo, mínimo y media *)


(* resultados_humedad(humedad); *)

(* A continuación se presenta la versión preliminar, menos modular *)


(*
presenta;
writeln('Introduzca los valores de las
temperaturas(01:00 hasta 24:00');
for i:= 1 to 24 do
begin
write('Temp. a las ', i, ': ');
readln(temperatura[i]);
end;

writeln('Temperatura media: ', Media(temperatura):0:1);


writeln('Temperatura Max: ', Maximo(temperatura));
writeln('Temperatura Min: ', Minimo(temperatura));
*)
end.

A continuación estudiaremos un tipo muy particular de tablas: las tablas de caracteres.

Cadenas de caracteres: strings

Hemos introducido el concepto de tabla y definido las tablas monodimensionales y su


uso. Más tarde estudiaremos las tablas multidimensionales.

Antes vamos a detenernos en un tipo muy particular de tabla monodimensional: las


tablas de caracteres, llamadas cadenas de caracteres. Las cadenas de caracteres no son
más que tablas unidimensionales cuyo tipo base es char. Para facilitar su uso en Pascal
se utiliza el tipo de datos string.

Definición

Para definirlas es necesario utilizar la palabra reservada string en vez de array:

type

cadena40 = string[40]; (* No se declara el tipo base *)


cadena80 = string[80];
cadena = string; (* Si no se especifica el tamaño es 255 *)

var

nombre = cadena40;
direccion = cadena80;
descripcion = cadena;
apellidos = string[50];

Como podemos observar es posible definir un tipo de datos string en la sección Type. O
definir variables de este tipo usando la palabra string directamente en la definición de la
variable.

En este tipo no se define el valor inicial y final de la tabla: sólo se define el tamaño. El
valor inicial se supone siempre que es uno (1). Luego el tipo cadena40 significa que
tenemos una tabla de 40 caracteres, y el índice varía desde 1 hasta 40.
En este tipo es opcional definir el tamaño de la cadena: si no lo hacemos se supone que
es 255. Hemos definido cadenas de distintos tamaños en función de las posibles
necesidades.

Acceso

Se puede acceder a los elementos de una cadena de caracteres de forma individual como en
las tablas, o hacer asignaciones directas utilizando el nombre de la variable:

apellidos[5] := 'L'; (* Acceso caracter a caracter *)


readln(apellidos[4]);

nombre := 'Felipe Fernandez'; (* Asignacion directa utilizando el nombre *)


readln(descripcion);
writeln(nombre);

Tamaño físico y longitud

Se puede observar que no siempre utilizamos todas las posiciones de una cadena. Por lo tanto
existen dos tamaños a utilizar cuando trabajamos con cadenas de caracteres o strings:

• El tamaño máximo o físico de la cadena.


• El tamaño que realmente estamos utilizando en cada momento. Este último se suele
denominar longitud, o tamaño lógico de la cadena.

En el caso de la variable nombre, su tamaño máximo o físico es 40, y su longitud tras la


asignación nombre := 'Felipe Fernandez'; es de 16.

Realmente el tamaño físico de la tabla es superior al esperado. Hemos mencionado


previamente que el índice de la cadena puede oscilar desde 1 hasta el tamaño del string.
El valor de índice cero (0) almacena el tamaño lógico de la cadena de caracteres en cada
momento. No es conveniente modificar este valor en nuestro programa porque
estaremos truncando nuestra cadena, y forzando una longitud lógica que no es la real.

Limitaciones

En el tipo string existen limitaciones similares a las tablas: no es posible que una función
devuelva como resultado una cadena ni definir este tipo de datos en la cabecera de un
módulo.

Tablas con índices no enteros

Por otra parte, los índices de las tablas pueden ser de cualquier tipo ordinal: enteros, carácter,
subrango, etc. Estudie el siguiente ejemplo, donde el índice de la tabla es de tipo carácter.

Se trata de solicitar al usuario una cadena de caracteres por pantalla y contar el número de
repeticiones de las distintas letras:
repeticiones: array['a'..'z'] of integer;
(* El índice indica la letra, y el valor que almacena el
número de repeticiones *)
...

for l:='a' to 'z' do


write(l,': ', repeticiones[l], ' ');

Observe la definición de la tabla y su uso posterior en un bucle. El algoritmo lo que hace es


recorrer la cadena de caracteres uno a uno, e ir incrementando el elemento de la tabla
repeticiones cuyo índice coincida con el valor de la cadena de caracteres (cadena[i]).

long := ord(cadena[0]);
(* La longitud lógica de una cadena se *)
(* almacena en el elemento 0 *)

for i:=1 to long do


repeticiones[cadena[i]] := repeticiones[cadena[i]] + 1;

Observe resaltados tanto el cálculo de la longitud de una cadena de caracteres (elemento


cero) como el acceso a los elementos de la tabla repeticiones para incrementarlos en una
unidad. El índice de la tabla repeticiones es el carácter i de la cadena (cadena[i]), que es
una letra.

El código completo de este ejemplo lo puede encontrar en [Link].

Intente mejorar este programa, creando procedimientos que hagan el cálculo de


ocurrencias y la presentación por pantalla de los resultados.

(*

Tema 7: Tablas

Programa ejemplo del uso de Tablas con índices no enteros.


Este programa cuenta el número de repeticiones de las letras
en una cadena que se solicita por pantalla.

*)

Program TablasLetras;

Var
i: integer; (* Var. auxiliar para bucles *)
long: integer; (* Longitud lógica de la cadena *)
l: char; (* Var. auxiliar para bucles *)
cadena: string; (* Var. que lamacena la cadena *)

repeticiones: array['a'..'z'] of integer;


(* El índice indica la letra, y el
valor que almacena el

número de repeticiones de esa letra *)

(* Modulo principal *)
begin
write('Introduzca una cadena de muestra: ');
readln(cadena);

long := ord(cadena[0]); (* La
longitud lógica de una cadena se *)

(*
almacena en el elemento 0 *)

for l:='a' to 'z' do (* inicia la


tabla repeticiones a cero *)
repeticiones[l] := 0;

for i:=1 to long do


repeticiones[cadena[i]] := repeticiones[cadena[i]] + 1;

(* Presenta por pantalla las ocurrencias de cada letra


*)
for l:='a' to 'z' do
write(l,': ', repeticiones[l], ' ');

end.

Pasemos a estudiar a continuación las tablas multidimensionales.

Tablas Multidimensionales

Las tablas multidimensionales se basan en el mismo concepto que las tablas


monodimensionales: un conjunto de elementos ordenado y homogéneo. Pero ahora el
acceso a los elementos se hace mediante más de un índice. De esta forma tendremos
tablas bidimensionales (dos índices), tridimensionales (tres índices), etc.

Definición

La definición de tipos o variables de este tipo es muy similar al de tablas


unidimensionales. La única diferencia es que tenemos varias dimensiones. Se define el
rango de cada índice como en tablas unidimensionales (inicio..fin), y cada rango se
separa del siguiente por comas (i1..f1, i2..f2, i3..f3):

type

nombre_tipo = array[vi_1..vf_1, v1_2..vf_2, ... vi_n..vf_n] of tipo_base;

var

nombre_var = array[vi_1..vf_1, v1_2..vf_2, ... vi_n..vf_n] of tipo_base;


Acceso a los elementos

El acceso a los elementos de una tabla mutidimensional se hace especificando un índice


para cada dimensión, separados estos por comas dentro de los corchetes:

nombre_var[ind_1, ind_2, ..... ind_n] := valor ;


readln(nombre_var[ind_1, ind_2, ..... ind_n]);

En el caso de una tabla bidimensional:

for i:=1 to 10 do
for j :=1 to 10 do
total := total + valor[i,j];

Es muy frecuente utilizar tablas de dos dimensiones para representar variables que son
funciones de dos parámetros distintos.

Estas tablas bidimensionales se corresponden con la información que representamos


habitualmente en filas y columnas. Podemos utilizar la primera dimensión para las filas
y la segunda para las columnas.

Esto es lo que se representa en la siguiente figura: tres filas por cinco columnas. En las
posiciones de las tablas hemos representado los índices necesarios para acceder a cada
elemento de al tabla.

Ejemplos de posible utilización de tablas bidimensionales son:

• Gastos mensuales clasificados por tipo de gastos: una dimensión puede representar
los meses y otra el tipo de gastos.
• Ventas de una empresa clasificadas por meses y por regiones.

• Notas de una clase por alumnos y asignatura.

A continuación vamos a estudiar el uso de tablas multidimensionales. Al mismo tiempo


iremos repasando los conceptos de modularidad, funciones y procedimientos.

Ejemplo: ventas

Estudie el siguiente programa: intentamos que una tabla refleje las ventas por meses y por
zonas de varios agentes comerciales.

Necesitamos una tabla bidimensional: las filas representan los meses y las columnas las
zonas.

Type
ventas = array[1..2, 1..4] of real;
(* Tabla para almacenar las ventas mensuales en cada región *)
(* Tenemos 12 meses (1..12) y 4 regiones (1..4) *)

Var
i: integer; (* Var. auxiliar para contadores *)
j: integer; (* Var. auxiliar para contadores *)
Cesar: ventas; (* Tabla que recoge las ventas de un
comercial 12 meses por 4 zonas *)

A continuación nuestro programa solicita al usuario los datos por meses y por zonas. Par ello
debe recorrer la tabla por filas y columnas. Es necesario un bucle que recorra las filas. Para
cada iteración de este bucle necesitamos un bucle interior que vaya recorriendo las columnas
de esa fila.

(* Observe: para "llenar" la tabla bidimensional necesitamos dos bucles for anidados. El
primero o exterior recorre las filas, y el segundo o interior recorre las columnas *)

for i:= 1 to 2 do (* recorre filas: desde Enero hasta Diciembre *)


begin

writeln('Ventas mes ', i);


for j:= 1 to 4 do (* recorre columnas: desde zona 1 hasta 4 *)
begin

write(' Zona ', j, ': ');


read(Cesar[i,j]);

end;

end;

Un bucle similar se utiliza para presentar los valores de la tabla por pantalla. El código
completo lo puede encontrar en tablasmulti_01.pas.

(*
Tema 7: Tablas

Tablasmulti_01

Programa ejemplo del uso de Tablas Multidimensionales en Pascal.


Define una tabla bidimensional: las filas on los meses, y las
columnas las
zonas de venta.

Nota: Para abreviar las pruebas se reduce el número de meses a


dos o tres

*)

Program TablasMulti_01;

Type
ventas = array[1..2, 1..4] of real;
(* Tabla para almacenar las ventas mensuales en cada
región *)
(* Tenemos 12 meses (1..12) y 4 regiones
(1..4) *)

Var
i: integer; (* Var. auxiliar para contadores *)
j: integer; (* Var. auxiliar para contadores *)
Cesar: ventas; (* Tabla que recoge las ventas de
un comercial

12 meses por 4
zonas *)

(* Modulo principal *)
begin

(* Lectura de las ventas anuales *)


writeln('Introduzca las ventas anuales');
writeln('*****************************');

(* Observe: para "llenar" la tabla bidimensional necesitamos


dos bucles for
anidados. El primero o exterior recorre las filas, y el
segundo o
interior recorre las columnas
*)

for i:= 1 to 2 do (* recorre filas: desde Enero hasta


Diciembre *)
begin
writeln('Ventas mes ', i);
for j:= 1 to 4 do (* recorre columnas:
desde zona 1 hasta 4 *)
begin
write(' Zona ', j, ': ');
read(Cesar[i,j]);
end;
end;

(* Para mostrar los valores de la tabla también necesitamos


dos bucles for
anidados. El primero o exterior recorre las filas, y el
segundo o
interior recorre las columnas
*)

(* Presentación de las ventas *)

for i:= 1 to 2 do (* recorre filas: desde Enero hasta


Diciembre *)
begin
write('Ventas mes ', i);
for j:= 1 to 4 do (* recorre columnas:
desde zona 1 hasta 4 *)
begin
write(' Zona ', j, ': ');
write(Cesar[i,j]:0:1,' ');
end;
writeln;
end;
end.
Edítelo, estudie el código y compile el programa. Ejecútelo para comprobar su
funcionamiento.

Pero esta es simplemente nuestra primera versión. Posiblemente tengamos varios


vendedores, y no sería muy elegante ni eficaz repetir los bucles de lectura y escritura
anteriores para cada uno ellos. Es necesario crear un procedimiento genérico para la
lectura y otro para la escritura. A estos habrá que pasarles como parámetro la tabla que
queremos actualizar o presentar por pantalla.

No olvide un detalle: ¿cómo se le debe pasar la tabla a la función de lectura?


Posiblemente ya lo haya descubierto: por referencia.

Además, a las funciones de lectura y escritura le vamos a pasar como parámetro una
cadena de caracteres para avisar al usuario del comercial del que se trata.

Procedure lee_ventas(VAR empleado: ventas; nombre: string);


Var

i,j: integer;

begin
(* Observe: para "llenar" la tabla bidimensional necesitamos dos bucles for anidados. El
primero o exterior recorre las filas, y el segundo o interior recorre las columnas *)

for i:= Enero to Diciembre do (* recorre filas: Enero hasta Diciembre *)


begin

writeln('Ventas de ', nombre,' mes ', i);


for j:= 1 to 4 do (* recorre columnas: desde zona 1 hasta 4 *)
begin

write(' Zona ', j, ': ');


readln(empleado[i,j]);

end;

end;

end;

Observe que:

• La tabla de ventas se pasa por valor o referencia.


• Se le pasa también una cadena de caracteres para ayudar a la presentación por
pantalla, y almacenará el nombre del vendedor.
• Se usa como límite del bucle más externo las constantes Enero y Diciembre, definidas
como 1 y 12 en la zona de constantes.
El cuerpo del programa principal queda mucho más legible:

(* Lectura de las ventas anuales *)


writeln('Introduzca las ventas anuales de Cesar ');
writeln('**************************************');
lee_ventas(Cesar, 'Cesar');
write_ventas(Cesar, 'Cesar');

Pero además de la legibilidad hemos conseguido que leer y presentar las ventas de
cualquier otro vendedor sea inmediato:

writeln('Introduzca las ventas anuales de Jesus ');


writeln('**************************************');
lee_ventas(Jesus, 'Jesus');
write_ventas(Jesus, 'Jesus');

Como puede observar, la modularidad es un concepto muy importante a la hora de modificar


o mejorar las prestaciones de un programa.

Y ahora seguramente querrá hacer algo con los datos de ventas, como por ejemplo
calcular el máximo de ventas de cada vendedor. Vamos a implementar una función que
reciba los datos de ventas de un empleado y devuelva el máximo de dichas ventas.

(* Calcula el máximo de ventas (en todos los meses y en todas las zonas de un
empleado que se le pasa como parámetro por valor *)
Function max_ventas(empleado: ventas): Real;
Var

max: Real;
i,j: integer;

begin

max := -1.0;
for i:= Enero to Diciembre do (* recorre filas: Enero hasta Diciembre *)
begin

for j:= 1 to 4 do(* recorre columnas: desde zona 1 hasta 4 *)

if (empleado[i,j] > max) then

max := empleado[i,j];

end;

max_ventas := max;

end;
Y la llamada a esta función será simplemente:

writeln('Maximos de ventas');
writeln('Cesar: ', max_ventas(Cesar):0:1);
writeln('Jesus: ', max_ventas(Jesus):0:1);

Observe como la llamada a la función max_ventas se realiza dentro de la función


writeln. El código completo se encuentra en el fichero tablamulti_02.pas. Si compila
este programa obtendrá un nuevo warning: de nuevo dejamos variables definidas pero
no utilizadas. Elimine las definiciones de esas variables y vuelva a compilar para que
desaparezcan los avisos.

(*

Tema 7: Tablas

Tablasmulti_02, versión mejorada de tablasmulti_01

Se añaden funciones para la lectura y escritura de las tablas.

Programa ejemplo del uso de Tablas Multidimensionales en Pascal.


Define una tabla bidimensional: las filas son los meses, y las
columnas las
zonas de venta.

Nota: Para abreviar las pruebas se reduce el número de meses a


dos o tres

*)

Program TablasMulti_02;
Const
Enero = 1; (* Constantes
para definir rango meses *)
Diciembre = 2;
Type
ventas = array[Enero..Diciembre,1..4] of real;
(* Tabla para almacenar las ventas mensuales en cada
región *)
(* Tenemos 12 meses (1..12) y 4 regiones
(1..4) *)

Var
i,j: integer;
Cesar, Jesus: ventas; (* Vendedores *)

(* Observe que la variable empleado se pasa por VALOR. Al mismo tiempo


*)
(* se pasa el nombre del empleado para facilitar la presentación
*)
Procedure lee_ventas(VAR empleado: ventas; nombre: string);
Var
i,j: integer;
begin
(* Observe: para "llenar" la tabla bidimensional necesitamos
dos bucles for
anidados. El primero o exterior recorre las filas, y el
segundo o
interior recorre las columnas
*)

for i:= Enero to Diciembre do (* recorre filas: Enero hasta


Diciembre *)
begin
writeln('Ventas de ', nombre,' mes ', i);
for j:= 1 to 4 do (* recorre columnas: desde zona 1 hasta
4 *)
begin
write(' Zona ', j, ': ');
readln(empleado[i,j]);
end;
end;
end;

(* Presenta los resultados de ventas por meses y zonas *)


Procedure write_ventas(empleado: ventas; nombre: string);
Var
i,j: integer;
begin
(* Para mostrar los valores de la tabla también necesitamos dos
bucles for
anidados. El primero o exterior recorre las filas, y el segundo o
interior recorre las columnas
*)

for i:= Enero to Diciembre do (* recorre filas: Enero hasta


Diciembre *)
begin
writeln('Ventas de ', nombre,' mes ', i);
for j:= 1 to 4 do (* recorre columnas: desde zona 1
hasta 4 *)
begin
write(' Zona ', j, ': ');
write(empleado[i,j]:0:0,' ');
end;
writeln();
end;
end;

(* Calcula el máximo de ventas (en todos los meses y en todas las


zonas
de un empleado que se le pasa como parámetro por valor *)
Function max_ventas(empleado: ventas): Real;
Var
max: Real;
i,j: integer;
begin
max := -1.0;
for i:= Enero to Diciembre do (* recorre filas: Enero hasta
Diciembre *)
begin
for j:= 1 to 4 do (* recorre columnas: desde zona 1
hasta 4 *)
if empleado[i,j] > max then
max := empleado[i,j];
end;
max_ventas := max;
end;

(* Modulo principal *)
begin
(* Lectura de las ventas anuales *)
writeln('Introduzca las ventas anuales de Cesar ');
writeln('**************************************');
lee_ventas(Cesar, 'Cesar');
write_ventas(Cesar, 'Cesar');

writeln('Introduzca las ventas anuales de Jesus ');


writeln('**************************************');
lee_ventas(Jesus, 'Jesus');
write_ventas(Jesus, 'Jesus');

(* Cálculo y presentación de máximos de ventas *)


writeln('Maximos de ventas');
writeln('Cesar: ',max_ventas(Cesar):0:1);
writeln('Jesus: ',max_ventas(Jesus):0:1);

end.

A partir de aquí las posibilidades son infinitas. Por ejemplo el tipo base de las tablas no
tiene por que ser un tipo básico: puede ser un tipo definido por el usuario. De esta forma
las posibilidades se multiplican, sobre todo cuando estudiemos en el tema siguiente los
registros.

Vamos a proponer un nuevo cambio: crear una tabla unidimensional, donde cada uno de
los elementos sea una tabla del tipo ventas.

Type
ventas = array[Enero..Diciembre, 1..NumZonas] of real;
(* Tabla para almacenar las ventas mensuales en cada región *)
(* Tenemos 12 meses (1..12) y 4 regiones (1..4) *)

vendedores = array[1..NumEmple] of ventas;


(* Tabla de vendedores: cada una de las posiciones almacena
las ventas de un comercial. El índice de la tabla será
el nombre del vendedor
*)

Var
plantilla: vendedores;

De esta forma no tendremos que modificar los procedimientos creados, sólo las llamadas o
invocaciones a estos procedimientos. Si a las funciones de los ejemplos anteriores se le pasaba
como parámetro una tabla del tipo ventas, ahora le pasaríamos como parámetro un elemento
de la tabla vendedores. Cada uno de estos elementos es del tipo ventas.

Las llamadas a las funciones de lectura y escritura del módulo principal quedarían de la
siguiente forma:

(* Lectura de las ventas de Angel *)


lee_ventas(plantilla[1], 'Angel');
write_ventas(plantilla[1], 'Angel');

(* Lectura de las ventas de Carmen *)


lee_ventas(plantilla[2], 'Carmen');
write_ventas(plantilla[2], 'Carmen');

Y podremos crear una función que a partir de lo anterior calcule el máximo de todos los
vendedores, aprovechando que ya tenemos una función que calcula el máximo de un
vendedor:

(* Calcula el máximo de ventas mensuales entre TODOS los empleados


*)
Function max_todos(empleados: vendedores ): Real;
Var
max: Real;
i: integer;
begin
max := -1.0;
for i:= 1 to NumEmple do
if max_ventas(empleados[i]) > max then
max := max_ventas(empleados[i]);

max_todos := max;
end;

Y la llamada a esta función quedaría:

writeln('TODOS : ', max_todos(plantilla):0:1);

El código final lo puede estudiar en tablasmulti_03.pas


Con este ejemplo hemos terminado el tema de tablas. Pasemos ahora a un nuevo tema:
los registros o estructuras.

(*
Tema 7: Tablas

Tablasmulti_03, versión mejorada de tablasmulti_02

Se crea un tabla cuyos elementos son tablas del tipo ventas. Es


similar a
una tabla de tres dimensiones.

Se añaden funciones para la lectura y escritura de las


tablas.

Programa ejemplo del uso de Tablas Multidimensionales en Pascal.


Define una tabla bidimensional: las filas son los meses, y
las columnas las
zonas de venta.

Nota: Para abreviar las pruebas se reduce el número de meses


a dos o tres
*)

Program TablasMulti_03;
Const
Enero = 1;
Diciembre = 2;
NumEmple = 2;
NumZonas = 2;
Type
ventas = array[Enero..Diciembre, 1..NumZonas] of real;
(* Tabla para almacenar las ventas mensuales en cada
región *)
(* Tenemos 12 meses (1..12) y 4 regiones
(1..4) *)

vendedores = array[1..NumEmple] of ventas;


(* Tabla de
vendedores: cada uan de las posiciones almacena
las ventas
de un comercial. El índice de la tabla será

el nombre del vendedor


*)
Var
plantilla: vendedores;

(* Solicita por pantalla las ventas por meses y regiones de un


vendedor *)
(* Observe que la variable empleado se pasa por VALOR. Al mismo tiempo
*)
(* se pasa el nombre del empleado para facilitar la presentación
*)
Procedure lee_ventas(VAR empleado: ventas; nombre: string);
Var
i,j: integer;
begin
(* Observe: para "llenar" la tabla bidimensional necesitamos
dos bucles for
anidados. El primero o exterior recorre las filas, y el
segundo o
interior recorre las columnas
*)

for i:= Enero to Diciembre do (* recorre filas: Enero hasta


Diciembre *)
begin
writeln('Ventas de ', nombre,' mes ', i);
for j:= 1 to NumZonas do (* recorre columnas: desde zona 1
hasta 4 *)
begin
write(' Zona ', j, ': ');
readln(empleado[i,j]);
end;
end;
end;

(* Presenta los resultados de ventas por meses y zonas *)


Procedure write_ventas(empleado: ventas; nombre: string);
Var
i,j: integer;
begin
(* Para mostrar los valores de la tabla también necesitamos dos
bucles for
anidados. El primero o exterior recorre las filas, y el segundo o
interior recorre las columnas
*)

for i:= Enero to Diciembre do (* recorre filas: Enero hasta


Diciembre *)
begin
writeln('Ventas de ', nombre,' mes ', i);
for j:= 1 to NumZonas do (* recorre columnas: desde zona 1
hasta 4 *)
begin
write(' Zona ', j, ': ');
write(empleado[i,j]:0:0,' ');
end;
writeln();
end;
end;

(* Calcula el máximo de ventas (en todos los meses y en todas las


zonas
de un empleado que se le pasa como parámetro por valor *)
Function max_ventas(empleado: ventas): Real;
Var
max: Real;
i,j: integer;
begin
max := -1.0;
for i:= Enero to Diciembre do (* recorre filas: Enero hasta
Diciembre *)
begin
for j:= 1 to NumZonas do (* recorre columnas: desde zona 1
hasta 4 *)
if empleado[i,j] > max then
max := empleado[i,j];
end;
max_ventas := max;
end;

(* Calcula el máximo de ventas mensuales entre TODOS los empleados


*)
Function max_todos(empleados: vendedores ): Real;
Var
max: Real;
i: integer;
begin
max := -1.0;
for i:= 1 to NumEmple do
if max_ventas(empleados[i]) > max then
max :=
max_ventas(empleados[i]);
max_todos := max;
end;

(* Modulo principal *)
begin

(* Lectura de las ventas de Angel *)


lee_ventas(plantilla[1], 'Angel');
write_ventas(plantilla[1], 'Angel');

(* Lectura de las ventas de Carmen *)


lee_ventas(plantilla[2], 'Carmen');
write_ventas(plantilla[2], 'Carmen');

writeln('Maximos de ventas');
writeln('Angel : ',max_ventas(plantilla[1]):0:1);
writeln('Carmen: ',max_ventas(plantilla[2]):0:1);
writeln('TODOS : ',max_todos(plantilla):0:1);

end.
Introducción

La finalidad de este tipo de datos es agrupar bajo un mismo nombre distintas


características o propiedades del objeto con el que estemos trabajando.
Un registro es un tipo de datos estructurado formado por un conjunto de una o más
variables agrupadas bajo un mismo nombre común, para hacer más eficiente e intuitivo
el manejo de estas variables.

A cada una de estas variables que forma parte del registro se le conoce como campo (o
atributo), y puede ser de cualquiera de los tipos explicados.

Si comparamos con el otro tipo estructurado que ya conocemos, las tablas, descubrimos
que:

• Los elementos de una tabla son todos del mismo tipo, es un conjunto
homogéneo.
• Los elementos de un registro pueden ser de distintos tipos, heterogéneos.

Por otra parte, el acceso a los miembros:

• De una tabla se hace mediante el nombre de la tabla y un índice.


• De un registro se hace mediante el nombre del registro y el nombre del
campo.

Podemos agrupar la información referente a una persona (que antes almacenábamos en


varias variables) en un registro, donde cada uno de los campos coincide con una de las
variables previas: nombre, edad, altura y peso. Gráficamente se podría representar:

O se pueden describir todas las características de un libro en una estructura:

• título
• autor
• editorial
• año de publicación
• etc.

O las características de un producto de una tienda:

• referencia
• código de barras
• color
• precio
• descuento asociado
• etc.

Pasemos a estudiar como se definen y usan los registros en Pascal.


Definición

Al igual que ocurre con las tablas, podemos definir variables de tipo registro
directamente en la sección de variables, o definir un tipo de usuario registro. Para
definir un registro se usa la palabra reservada record. A continuación se definen los
distintos campos del registro junto con sus tipos. Esto es lo que podemos observar en el
siguiente ejemplo:

Type
persona = record
nombre : string;
edad : integer;
peso : real;
altura : real;
end;

Var
alumno : persona;
profesor : record
nombre : string;
edad : integer;
peso : real;
altura : real;
end;
alumno1, alumno2 : persona;

El tipo de datos persona es un registro con cuatro campos y sus correspondientes tipos:
nombre, edad, peso y altura. Una vez definido el tipo de usuario persona se pueden
definir variables del tipo persona.

También se muestra como definir un registro en la sección de variables. El problema es


que al hacerlo de esa forma no se podrá pasar como parámetro a funciones o
procedimientos, la misma situación que ya estudiamos con tablas.

Acceso a los elementos

Para acceder a los elementos basta con utilizar el nombre de la variable, seguido de un punto y
el nombre del campo. De esta forma se puede usar ese campo como una variable más en
nuestro código:

[Link] := 'Fermin Alerce Herranz';


[Link] := 48;

writeln('Nombre : ', [Link]);


writeln('Edad : ', [Link]);

write('Peso : ');
readln([Link]);

write('Altura : ');
readln([Link]);

ratio = [Link]/[Link];
Operaciones con registros

La única operación permitida con un registro como conjunto es la asignación:

alumno1 := alumno;

Y además se debe cumplir no sólo que respondan a la misma estructura, sino que el tipo
asociado en sus definiciones sea el mismo. Según esto, la sentencia:

profesor := alumno; (* Atención: No compila *)

no compilaría por que la definición de tipos no es la misma.

Por otra parte, no se pueden comparar dos registros de la forma habitual, con el
operador =

if ( alumno1 = alumno2 ) then (* Error: operación no permitida *)

Será necesario comparar los campos uno a uno. Para ello se puede codificar una función como
la siguiente:

(* Compara dos registros del tipo persona campo a campo y devuelve TRUE o FALSE
*)
Function compara_persona(per1, per2 : persona): Boolean;
Begin

compara_persona := ([Link] = [Link])

AND ([Link] = [Link])


AND ([Link] = [Link])
AND ([Link] = [Link]);

End;

Y usarla como se muestra a continuación:

if ( compara_persona(alumno1,alumno2) ) then
writeln('Alumno1 y alumno2 son iguales')
else
writeln('Alumno1 y alumno2 NO son iguales');

Pasemos a estudiar ejemplos de uso de registros en Pascal.


Uso de Registros

Aunque es posible asignar valores a los campos de un registro uno a uno, lo más habitual es
crear un procedimiento que se encargue de la lectura de todo el registro. Observe en el
siguiente ejemplo que es necesario pasar el parámetro por referencia.

(* Lee del teclado toda la información de una persona que se le pasa


*)
(* como parámetro por referencia *)
Procedure read_persona(VAR alumno : persona);
Begin
write('Nombre : ');
readln([Link]);
write('Edad : ');
readln([Link]);
write('Peso : ');
readln([Link]);
write('Altura : ');
readln([Link]);
End;
Del mismo modo creamos un procedimiento para agrupar la presentación de un registro por
pantalla en una función. En este caso no es necesario pasar el registro por referencia:

(* Presenta por pantalla toda la información de un registrodel


tipo persona que se le pasa como parámetro *)
Procedure write_persona(alumno : persona);
Begin
writeln;
writeln('Nombre : ', [Link]);
writeln('Edad : ', [Link]);
writeln('Peso : ', [Link]:1);
writeln('Altura : ', [Link][Link]);
writeln;
End;

El uso de estas funciones es bastante sencillo. Además puede observar que el uso de registros
como parámetros de funciones es similar al uso de tablas.

read_persona(alumno2);
write_persona(alumno2);

Registros anidados

Es posible incluso que alguno de los campos de un registro sea a su vez otro registro: en este
caso es necesario que el registro "interior" se defina primero.

Type
Tpersona = record
(* Tipo que define las caracteristicas de una persona *)
nombre : string[TAMNOMBRE];
dni : string[TAMDNI];
edad : integer;
end;
Talumno = record
datos : Tpersona;
teoria : real;
practica : real;
end;

Var
Juan: Talumno;

Observe que el identificador de tipo se ha precedido con una 'T'. A veces se usa esta notación
para hacer más evidente que se esta usando un Tipo definido por el usuario. Para acceder a los
campos del registro anidado o interior se usa el operador ".":

write('Nombre: ');
readln([Link]);
write('Edad: ');
readln([Link]);
write('Nota Teoria: ');
readln([Link]);
write('Nota Practica: ');
readln([Link]);

Estudiemos ahora una de las aplicaciones más frecuentes de los registros: las tablas de
registros.
Tablas de registros

Vamos a utilizar en este apartado las dos estructuras compuestas estudiadas: tablas y
registros.

Si ya hemos visto como agrupar la información, por ejemplo, de un alumno, ¿por qué
no agrupamos a los alumnos, del tipo Talumno en una tabla para poder tratar a toda la
clase de forma homogénea?

Observe las siguientes definiciones

Const
TAMCLASE = 10;
TAMNOMBRE = 30;
TAMDNI = 13;
Type
Tpersona = record (* Tipo registro que define las
características de una persona *)
nombre : string [TAMNOMBRE];
dni: string[TAMDNI];
edad: integer;
end; (* Tipo que define las caracteristicas de un
alumno: persona +notas *)

(* Es un ejemplo de registro anidado *)


Talumno = record
datos: Tpersona;
teoria: real;
practica: real;
end;

(* Tabla de registros del tipo Talumno *)


Tclase = array[1..TAMCLASE] of Talumno;
Var
edad: real; (* Edad media de la clase *)
miclase: Tclase; (* Define miclase como tabla de alumos
*)
alumno: Talumno;
De esta forma se puede tratar cada elemento de la tablamiclase (miclase[i]) como una variable
de tipo Talumno:

write('Nombre: ');
readln(miclase[i].[Link]);

write('Edad: ');
readln(miclase[i].[Link]);

write('Nota Teoria: ');


readln(miclase[i].teoria);

write('Nota Practica: ');


readln(miclase[i].practica);
Claro que no debemos olvidar que lo que hacía verdaderamente potente a las tablas es la
posibilidad de tratar todos los elementos de la tabla mediante bucles.

Si suponemos codificadas las funciones read_alumno y write_alumno, se pueden


codificar las siguientes funciones para la lectura y escritura de los datos de toda la clase:

(* Procedimiento inicial para la lectura de la clase *)


Procedure lee_clase(VAR unaclase: Tclase);
Var
i : integer;
Begin
for i:= 1 to TAMCLASE do
read_alumno(unaclase[i]);
End;

Procedure escribe_clase(unaclase: Tclase);


Var
i : integer;
Begin
for i:= 1 to TAMCLASE do
write_alumno(unaclase[i]);
writeln;
End;
Observe:

• El paso de parámetros a la función de lectura por REFERENCIA,


• y a la función de escritura por VALOR.
• Al mismo tiempo observe los bucles de ambas funciones,
• y cómo se utilizan las funciones read_alumno y write_alumno: Se le pasan como
parámetro un elemento de la tabla, que será del tipo alumno.

Una vez que tiene los datos de su clase querrá hacer algún tipo de cálculos con ellos. Vamos a
realizar como ejemplo una función que nos presente por pantalla la edad media de la clase.

Para ello necesitamos que la función reciba como parámetro toda la clase. ¿Por valor o
por referencia? Recuerde: si no va a modificar el parámetro se debe pasar por valor.

Debemos codificar un bucle que vaya recorriendo cada elemento de la tabla (la clase) y
sumando la edad de cada alumno. Finalizado el bucle, dividimos por el número de
alumnos. El código resultante es:

Procedure edad_media(unaclase: Tclase);


Var
i : integer;
suma : real;
media: real;
Begin
suma := 0;
for i:= 1 to TAMCLASE do
suma := suma + unaclase[i].[Link];
media := suma/TAMCLASE;
writeln('La edad media de la clase es de ', medi[Link]);
End;
Puede estudiar todo el código de estos ejemplos en [Link].
(*
Tema 8: Registros

Programa ejemplo del uso de registros:


- definición
- acceso a los campos
- uso con funciones
- registros anidados
- tablas de registros
*)
Program Registros04;

Const
TAMCLASE = 2;
TAMNOMBRE = 30;

Type
Tpersona = record (* Tipo que define las caracteristicas
de una persona *)
nombre : string[TAMNOMBRE];
edad : integer;
end;

Talumno = record
datos : Tpersona;
teoria : real;
practica : real;
end;

Tclase = array[1..TAMCLASE] of Talumno;

Var
miclase : Tclase; (* Define miclase como tabla de
personas *)
alu01 : Talumno;

(* Presenta por pantalla toda la información de una persona que se le


pasa *)
(* como parámetro
*)
Procedure write_persona(persona : Tpersona);
Begin
writeln;
write('Nombre: ', [Link]);
write(' Edad: ', [Link]);
writeln;
End;

(* Presenta por pantalla toda la información del alumno que se le pasa


*)
(* como parámetro
*)
(* Aunque se podría codificar esta función partendo de cero, vamos a
*)
(* codificarla partiendo de write_persona, para reutilizar el código
*)
Procedure write_alumno(alumno : Talumno);
Begin
write_persona([Link]);
write(' Teoria: ', [Link][Link], ' Practica: ',
[Link][Link]);
write(' Nota media: ', ([Link]+[Link])/[Link]);
End;

(* Lee del teclado toda la información de una persona que se le pasa


*)
(* como parámetro por referencia
*)
Procedure read_persona(VAR alumno : Tpersona);
Begin
writeln;
write('Nombre : ');
readln([Link]);

write('Edad : ');
readln([Link]);
writeln;
End;

(* Presenta por pantalla toda la inforamción del alumno que se le pasa


*)
(* como parámetro
*)
(* Aunque se podría codificar esta función partendo de cero, vamos a
*)
(* codificarla partiendo de write_persona, para reutilizar el código
*)
Procedure read_alumno(VAR alumno : Talumno);
(* Pruebe a no pasar alumno por referencia... *)
Begin
read_persona([Link]);
write('Nota Teoria: ');
readln([Link]);

write('Nota Practica: ');


readln([Link]);
End;

(* Procedimiento para la lectura de la clase *)


Procedure lee_clase(VAR unaclase: Tclase);
Var
i : integer;
Begin
i := 1;
for i:= 1 to TAMCLASE do
begin
read_alumno(unaclase[i]);
end;
End;

(* Procedimiento para presentar por pantalla los datos de la clase *)


Procedure escribe_clase(unaclase: Tclase);
Var
i : integer;
Begin
for i:= 1 to TAMCLASE do
write_alumno(unaclase[i]);
writeln;
End;

(* Calcula la edad media de al clase. *)


Procedure edad_media(unaclase: Tclase);
Var
i : integer;
suma : real;
media: real;
Begin
suma := 0;
for i:= 1 to TAMCLASE do
suma := suma + unaclase[i].[Link];
media := suma/TAMCLASE;
writeln('La edad media de la clase es de ', medi[Link]);

End;

(* Programa principal *)
Begin

lee_clase(miclase);
escribe_clase(miclase);

edad_media(miclase);

End.
Introducción

Todo lo estudiado hasta ahora sería poco útil si no existiese alguna forma de hacer que
nuestros datos se puedan guardar de forma permanente entre las distintas ejecuciones de
un programa.

Hasta ahora nuestros datos desaparecían tras utilizar un programa. Sin ir más lejos, en
los programas que gestionaban los alumnos de una clase, era bastante tedioso tener que
introducir todos los datos de la clase (nombres, notas, etc.) cada vez que se necesitaba
trabajar con nuestro programa.

Esto se debe a que los datos de nuestro programa se almacenan durante la ejecución del
programa en la memoria principal del ordenador. Esta memoria es volátil, y además se
libera cuando terminamos de usar el programa.

Para evitar esto se usan los dispositivos de almacenamiento externo (o memoria


secundaria). En nuestro caso, estamos hablando de los disquetes o del "disco duro" de
su ordenador. En estos la información se organiza de forma jerárquica en ficheros.

El nombre de un fichero se compone de dos partes, nombre y extensión, separados por


el carácter punto (.). Aunque la longitud del nombre puede depender del sistema
operativo que esté usando, le recomendamos que use nombre de 8 caracteres, y tres para
la extensión.

[Link]
La extensión se utiliza para distinguir el tipo del contenido del fichero. De esta forma, si
vemos un fichero con extensión ".c", sabremos que se trata de un fichero con un
programa en lenguaje C. Y como ya hemos observado, los ficheros que contienen
programas en Pascal usan la extensión ".pas".

Usaremos los ficheros para almacenar información como:

• Los datos de una clase.


• Valores diarios de las temperaturas: mínimo, máximo y media.
• Los datos de una consulta médica.
• etc.

Como los soportes de almacenamiento secundario son más lentos que la memoria
principal, la forma de trabajar es leer del fichero los datos con los que se va a trabajar y
utilizarlos en la memoria principal.

Estudiemos como se utilizan en Pascal los ficheros.


Para usar los ficheros es necesario definirlos primero, y a continuación usar las
funciones y procedimientos que estudiaremos a continuación.

Definición

Un fichero es una secuencia de elementos del mismo tipo. Por lo tanto para definir un
fichero es necesario determinar primero el tipo base de ese fichero. El proceso habitual
es definir primero el tipo base, y a continuación el tipo fichero.

La forma de hacerlo es:

Tipo_fichero = file of Tipo_base; (* Define un tipo de fichero de Tipo_base *)

En el siguiente ejemplo se define un tipo de datos Talumno de tipo registro, y este se


utilizará como tipo base para un tipo definido por el usuario de nombre Tfichero. Ya
tenemos los tipos definidos por el usuario. Sólo restaría definir una variable del tipo del
fichero:

Const
TAMCLASE = 10;
TAMNOMBRE = 30;
TAMDNI = 13;
Type
Tpersona = record
(* Tipo que define las caracteristicas de una persona *)
nombre : string[TAMNOMBRE];
dni : string[TAMDNI];
edad : integer;
end;

Talumno = record
(* Tipo que define las caracteristicas de un alumno *)
datos : Tpersona; (* Registro anidado *)
teoria : real;
practica : real;
end;

Tfichero = file of Talumno;


(* Define un fichero de tipo base Talumno *)

Var
fichero : Tfichero;

Asignación

Es la operación de asociar un fichero físico a una variable del tipo fichero. Una vez
realizada esta asociación, utilizaremos la variable de tipo fichero para todas las
operaciones relativas al fichero físico.
assign(fichero, '[Link]');

Apertura
Una vez asignado un fichero a una variable tipo fichero, es necesario "abrirlo" para
permitir operaciones de lectura o escritura. Para ello es posible utilizar dos
procedimientos:

• reset: Abre un archivo ya existente para una operación de lectura. Si el archivo


no existe se produce un error.
reset(fichero);
• rewrite: Crea un nuevo archivo. Si el archivo ya existe, borra su contenido.
rewrite(fichero);

Escritura

Una vez abierto el fichero, podemos escribir en él datos del tipo base del fichero. Para
ello disponemos del procedimiento write, al que se le indica en que fichero se escriben
los datos: write(fichero, var1, var2, .. varn); Si aprovechamos el código del programa de
gestión de la clase podemos crear un bucle donde se vayan guardando todos los
alumnos en fichero:
for i:= 1 to numeroalumnos do
write(fichero, miclase[i]);

Lectura

Si el fichero se abrió para lectura, el procedimiento, como ya puede imaginar, es read, y


la sintaxis muy similar a la de write:
read(fichero, var1, var2, ... varn);

Partiendo del ejemplo anterior, una vez almacenada la clase en fichero, la podemos
recuperar con el bucle:
for i:= 1 to numeroalumnos do
read(fichero, miclase[i]);

Cierre de un fichero

Una vez hayamos terminado de trabajar con el fichero, es necesario cerrarlo, con el
procedimiento close, cuyo único parámetro es el fichero:
close(fichero);

Otros procedimientos

filepos
A menudo es necesario conocer en que registro del fichero abierto estamos en cada
momento. Para ello se usa el procedimiento filepos, que recibe como parámetro la
variable de tipo fichero:
filepos(fichero);

Devuelve como resultado un entero que indica la posición del fichero en la que nos
encontramos. Los registros dentro de un fichero se numeran a partir de cero. Por lo
tanto, si tenemos tres registros en el fichero, se numeran de 0 a 2.
pos := filepos(fichero);

filesize

Esta función devuelve un entero que representa el número de registros que almacena un
fichero:
numelem := filesize(fichero);

seek

Con este procedimiento podemos colocarnos en un registro determinado del fichero,


indicando su posición:
seek(fichero, posicion);

Si queremos modificar un registro que acabamos de leer de un fichero, como la


operación de lectura hace que avancemos al siguiente registro, deberemos retroceder
una posición antes de escribirlo de nuevo:
/* Lee un registro del fichero */
read(fichero, registro);

/* Llama a un procedimiento que modifica el registro */


modifica(registro);

/* Calcula la posición del registro leido */


pos := filepos(fichero) -1;

/* Posiciona la siguiente lectura/escritura en pos */


seek(fichero, pos);

/* Escribe el registro modificado en el fichero


en la misma posición que tenía */
write(fichero, registro);

Estudiemos ahora ejemplos de la utilización de ficheros.


Ficheros: Ejemplos de Uso

En el caso que le proponemos vamos a modificar el programa de gestión de temperaturas para


que podamos almacenar en ficheros los datos diarios.

En un sistema real los datos de lectura del termómetro posiblemente se almacenarán


automáticamente en ficheros, usando como nombre una secuencia de dígitos que
incluya el día, mes y año. De esta forma "[Link]" representa los valores de
temperaturas del día 28 de Diciembre de 1999.

Lo que necesitamos es que nuestro programa sea capaz de leer los datos de temperatura
de un fichero para calcular medias, máximos y mínimos. Del mismo tiempo debe ser
posible guardar los datos en un fichero para su posterior lectura.

El menú principal de nuestro programa tendrá una estructura similar a:

writeln('Centro de control de medidas atmosfericas');


writeln('-----------------------------------------');

writeln;
writeln(' 1. Lectura de datos');
writeln(' 2. Presentacion de medidas');
writeln(' 3. Calculo de media, maximos y minimos');

writeln(' 5. Lectura de datos de fichero');


writeln(' 6. Guardar datos en fichero');
writeln;
writeln(' 9. Salir');
write(' Opción: ');

Para ello vamos a utilizar las siguientes constantes, tipos y variables:


Program Lab01;
Const
primhora = 1;
ulthora = 3; (* 24 *)
Type
lecturas = array[primhora..ulthora] of integer;
Tfichero = file of integer;
Var
temperatura : lecturas;
(* Almacena temperaturas cada hora *)
opc : integer;
(* Opción del menu elegida *)
nombre : string;
(* Almacena nombre del fichero de datos *)

Nos creamos una función que se encarga de guardar los datos en fichero, donde hemos
destacado en negrita los procedimientos relacionados directamente con ficheros: assign,
rewrite, write y close.

Procedure graba_fichero(nombre: string; VAR medidas :lecturas);


Var
i : integer;
fichero : Tfichero;
Begin

assign(fichero, nombre);
rewrite(fichero);

for i:= primhora to ulthora do


write(fichero, medidas[i]);

close(fichero);

End;

Del mismo modo creamos un función que lea los datos de fichero con los procedimientos
assign, reset, read y close.

También se usa la función eof, que recibe como parámetro un fichero y devuelve si
hemos alcanzado o no el final de ese fichero, y por lo tanto ya no hay más datos:

Procedure lee_fichero(nombre: string ;VAR medidas :lecturas);


Var
i: integer;
fichero : Tfichero;
Begin
i := 0;

assign(fichero, nombre);
reset(fichero);

while ( not(eof(fichero)) AND (i < ulthora) ) do begin


i := i+1;
read(fichero, medidas[i]);
end;

close(fichero);
End;

Las modificaciones a estos procedimientos en el programa principal serán:

write('Introduca el nombre del fichero de datos: ');


readln(nombre);
graba_fichero(nombre, temperatura);

Para llamar al procedimiento de lectura será necesario que el nombre de fichero que le
indiquemos exista previamente y almacene datos del tipo base del fichero:

write('Introduca el nombre del fichero de datos: ');


readln(nombre);
lee_fichero(nombre, temperatura);

El código completo lo puede consultar en [Link].


(*

Tema 9: Ficheros

Programa ejemplo del uso de Tablas y FICHEROS en Pascal


Toma medidas de temperatura y humedad y calcula la media, max y
minimo
*)

Program Lab01;
Const
primhora = 1;
ulthora = 3; (* 24 *)
Type
lecturas = array[primhora..ulthora] of integer;
Tfichero = file of integer;
Var
temperatura : lecturas; (* Almacena temperaturas cada hora
*)
opc : integer; (* Opción del menu elegida
*)
nombre : string; (* Almacena nombre del fichero
de datos *)

(*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!*)
(*!!!!!!!!!!!!!!!! Funciones matemáticas
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*)
(*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!*)
Function Media(medidas: lecturas): Real;
Var
i: integer;
suma: integer;
Begin
suma := 0;
for i:= primhora to ulthora do
suma:= suma + medidas[i];
Media := suma/(1.0+ulthora-primhora);
End;

Function Maximo(medidas: lecturas): Integer;


Var
i: integer;
max: integer;
Begin
max := medidas[primhora];
for i:= primhora+1 to ulthora do
if max < medidas[i] then
max := medidas[i];
Maximo := max;
End;

Function Minimo(medidas: lecturas): Integer;


Var
i: integer;
min: integer;
Begin
min := medidas[primhora];
for i:= primhora+1 to ulthora do
if min > medidas[i] then
min := medidas[i];
Minimo := min;
End;
(*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!*)
(*!!!!!!!!!!!!!!!! Funciones E/S
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*)
(*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!*)
(* Funcion de lectura de resultados por pantalla *)
Procedure Lectura(VAR medidas: lecturas; tipo: string[15]);
Var
i: integer;
Begin
writeln('Introduzca los valores de ', tipo,
'(', primhora, ':00, ' ,ulthora,':00)');
for i:= primhora to ulthora do
begin
write('Medida a las ', i, ': ');
readln(medidas[i]);
end;
End;

(* Funciones de presentación de resultados en pantalla *)


Procedure Escritura(medidas: lecturas; tipo: string[15]);
Var
i: integer;
Begin
writeln('Valores de ', tipo,
'(', primhora, ':00, ' ,ulthora,':00)');

for i:= primhora to ulthora do


begin
write(i, ': ', medidas[i],' ');
end;
writeln;
End;

(* Presenta estadisticas de las muestras*)


Procedure Resultados( medidas: lecturas; tipo: string[15]);
Begin
writeln;
writeln(tipo,' media: ', Media(medidas):0:1);
writeln(tipo,' Max: ', Maximo(medidas));
writeln(tipo,' Min: ', Minimo(medidas));
writeln;
End;

(*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!*)
(*!!!!!!!!!!!!!!!! Funciones de uso de ficheros
!!!!!!!!!!!!!!!!!!!!!!!!*)
(*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!*)
(* Almacena datos leidos en un fichero *)
Procedure graba_fichero(nombre: string; VAR medidas :lecturas);
Var
i : integer;
fichero : Tfichero;
Begin
assign(fichero, nombre);
rewrite(fichero);

for i:= primhora to ulthora do


write(fichero, medidas[i]);

close(fichero);
End;

(* Lee datos de fichero *)


Procedure lee_fichero(nombre: string ;VAR medidas :lecturas);
Var
i: integer;
fichero : Tfichero;
Begin
i := 0;

assign(fichero, nombre);
reset(fichero);

while ( not(eof(fichero)) AND (i<ulthora) ) do begin


i := i+1;
read(fichero, medidas[i]);
end;

close(fichero);
End;

(* Función que presenta menú y devuleve opción elegida *)


Function Menu: Integer;
Var
opc: integer;
Begin
repeat
writeln('Centro de control de medidas atmosféricas');
writeln('-----------------------------------------');
writeln;
writeln(' 1. Lectura de datos');
writeln(' 2. Presentación de medidas');
writeln(' 3. Cálculo de media, maximos y minimos');

writeln(' 5. Lectura de datos de fichero');


writeln(' 6. Guardar datos en fichero');
writeln;
writeln(' 9. Salir');
write(' Opción: ');
readln(opc);
until ( (opc>=1 and opc <=4) or (opc=9) );

Menu := opc;
End;

(*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!*)
(*!!!!!!!!!!!!!!!! PROGRAMA principal
!!!!!!!!!!!!!!!!!!!!!!!!!!!*)
(*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!*)
begin

repeat
opc := Menu; (* Presenta menú por pantalla y devuelve opcion
elegida*)
case opc of
1: lectura(temperatura,'Temperatura' );
2: escritura(temperatura,'Temperatura' );
3: resultados(temperatura, 'Temperatura');
5: begin
write('Introduca el nombre del fichero de
datos: ');
readln(nombre);
lee_fichero(nombre, temperatura);
end;
6: begin
write('Introduca el nombre del
fichero de datos: ');
readln(nombre);
graba_fichero(nombre, temperatura);
end;
end;
until (opc=9);

End.

Pruebe a compilarlo e introducir algunos valores de temperaturas. Observe que para no


hacer tediosa la introducción de temperaturas se ha limitado el número de muestras a
tres mediante la constante ultimahora.

Una vez introducidas las temperaturas presente los resultados en pantalla, y a


continuación guarde las muestras en fichero.

Si desconfía del programa (lo cual es una postura muy razonable), termine la ejecución
del programa con la opción "Salir". A continuación compruebe si se ha creado un
fichero con el nombre que usted eligió. Si lo intenta abrir con un editor (WordPad, Bloc
de Notas, . . Word, etc.), comprobará que su contenido no es el esperado. No debe
cundir el desánimo: los ficheros con tipos no se pueden leer directamente con editores
de texto.

Vuelva a ejecutar el programa. Antes de hacer nada, presente los datos (opción 2).
Evidentemente no hay datos, están a cero. Use ahora la opción leer de fichero. Teclee el
nombre previamente elegido, y compruebe que están los datos tal como usted los
introdujo.

Pruebe a modificar el programa para mejorar la presentación de los datos, y para tomar
un mayor número de muestras.

Vamos a estudiar a continuación un tipo especial de ficheros: los ficheros de texto.


Ficheros de texto

Un fichero de texto es aquel que contiene una cantidad indeterminada de cadenas de


caracteres de distintos tamaños.

Los archivos de texto se organizan en líneas separadas por el carácter fin de línea (end
of line, eol). Por lo tanto un fichero de texto es un conjunto de líneas de distinta longitud
separadas por el carácter eol. El final del fichero, al igual que en los ficheros con tipo, se
marca con eof (end of file).

Tambien se utilizan este tipo de ficheros cuando es necesario que los datos se puedan
visualizar con editores de texto. Los procedimientos para definir, leer, escribir y cerrar
ficheros son muy similares a los de ficheros con tipos.

Definición

En los ficheros de texto el tipo base del fichero es el tipo char. Los ficheros de texto se definen
directamente con la palabra reservada Text:

Tipo_fichero = Text; (* Define un tipo de fichero de tipo texto


*)

y en un ejemplo real obtenemos:

Program Lab02;
Const
primhora = 1;
ulthora = 3; (* 24 *)
Type
lecturas = array[primhora..ulthora] of integer;
Tfichero = text;
Var
fichero : Tfichero
fichero1 : Text;

Asignar, abrir, y cerrar fichero

Son los mismos procedimientos estudiamos para archivos con tipo:

assign(fichero, '[Link]');
reset(fichero);
rewrite(fichero);
close(fichero);

Escritura

Aquí aparecen las primeras diferencias con los ficheros con tipo. Podemos escribir o almacenar
datos en el fichero de distintos tipos y con distintas longitudes. Recuerde que en los ficheros
con tipos todos los datos deben ser del mismo tipo: del tipo base del fichero.
write(fichero, var1, var2, ... varn);
writeln(fichero, var1, var2, ... varn);
/* guarda caracter nueva línea tras variables */
Donde var1, var2, ... varn pueden ser de distintos tipos.

Modificando el ejemplo de las medidas atmosféricas:

for i:= primhora to ulthora do


writeln(fichero, medidas[i], ' a las ', i);

que sería equivalente a

for i:= primhora to ulthora do begin


write(fichero, medidas[i]);
write(fichero, ' a las ');
writeln(fichero, i);
end;

Observe:

• Usamos el procedimiento writeln. Este imprime una marca de fin de línea (eol) cuando
ha terminado de almacenar en el fichero todos sus parámetros.
• Tenemos tres argumentos de distintos tipos.

El contenido del fichero resultante sería algo similar a:


17 a las 1
16 a las 2
15 a las 3
14 a las 4

Lectura

Al igual que en la escritura, podemos leer datos de distintos tipos con el procedimiento read y
readln. Este último provocará que una vez leídos los argumentos, se salte a la siguiente línea.
Incluso se puede ignorar el resto de la línea si quedan datos en la línea por leer y no nos
interesan:

while ( not(eof(fichero)) AND (i < ulthora) ) do begin


i := i+1;
readln(fichero, medidas[i]);
end;
Según el formato del ejemplo anterior, tras leer la temperatura y asignarla a medidas[i] se
salta a la siguiente línea, sin leer el resto de caracteres de esa misma línea: " a las ", y la hora
de la muestra.

El código completo lo puede consultar en [Link].


(*
Tema 9: Ficheros

Programa ejemplo del uso de Tablas y FICHEROS de TEXTO en Pascal


Toma medidas de temperatura y humedad y calcula la media, max y
minimo
*)
Program Lab02;
Const
primhora = 1;
ulthora = 4; (* 24 *)
Type
lecturas = array[primhora..ulthora] of integer;
Tfichero = text;
Var
temperatura: lecturas; (* Almacena temperaturas cada hora
*)
opc: integer; (* Opción del menu elegida
*)
nombre: string; (* Almacena nombre del fichero
de datos *)

(*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!*)
(*!!!!!!!!!!!!!!!! Funciones matemáticas
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*)
(*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!*)
Function Media(medidas: lecturas): Real;
Var
i: integer;
suma: integer;
Begin
suma := 0;
for i:= primhora to ulthora do
suma:= suma + medidas[i];
Media := suma/(1.0+ulthora-primhora);
End;

Function Maximo(medidas: lecturas): Integer;


Var
i: integer;
max: integer;
Begin
max := medidas[primhora];
for i:= primhora+1 to ulthora do
if max < medidas[i] then
max := medidas[i];
Maximo := max;
End;

Function Minimo(medidas: lecturas): Integer;


Var
i: integer;
min: integer;
Begin
min := medidas[primhora];
for i:= primhora+1 to ulthora do
if min > medidas[i] then
min := medidas[i];
Minimo := min;
End;
(*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!*)
(*!!!!!!!!!!!!!!!! Funciones E/S
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*)
(*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!*)
(* Funcion de lectura de resultados por pantalla*)
Procedure Lectura(VAR medidas: lecturas; tipo: string[15]);
Var
i: integer;
Begin
writeln('Introduzca los valores de ', tipo,
'(', primhora, ':00, ' ,ulthora,':00)');
for i:= primhora to ulthora do
begin
write('Medida a las ', i, ': ');
readln(medidas[i]);
end;
End;

(* Funciones de presentación de resultados por pantalla*)


Procedure Escritura(medidas: lecturas; tipo: string[15]);
Var
i: integer;
Begin
writeln('Valores de ', tipo,
'(', primhora, ':00, ' ,ulthora,':00)');

for i:= primhora to ulthora do


begin
write(i, ': ', medidas[i],' ');
end;
writeln;
End;

(* Presenta estadisticas de las muestras*)


Procedure Resultados( medidas: lecturas; tipo: string[15]);
Begin
writeln;
writeln(tipo,' media: ', Media(medidas):0:1);
writeln(tipo,' Max: ', Maximo(medidas));
writeln(tipo,' Min: ', Minimo(medidas));
writeln;
End;

(*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!*)
(*!!!!!!!!!!!!!!!! Funciones de ficheros
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*)
(*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!*)
(* Almacena datos leidos en un fichero:
el nombre del fichero es el primer parámetro *)
Procedure graba_fichero(nombre: string; VAR medidas :lecturas);
Var
i : integer;
fichero : Tfichero;
Begin
assign(fichero, nombre);
rewrite(fichero);
(*
for i:= primhora to ulthora do
writeln(fichero, medidas[i], ' a las ', i);
*)
for i:= primhora to ulthora do begin
write(fichero, medidas[i]);
write(fichero, ' a las ');
writeln(fichero, i);
end;

close(fichero);
End;

(* Lee datos de fichero: el nombre del fichero es el primer parámetro


*)
Procedure lee_fichero(nombre: string ;VAR medidas :lecturas);
Var
i: integer;
fichero : Tfichero;
cad : string;
hora: integer;
Begin
i := 0;

assign(fichero, nombre);
reset(fichero);
(*
while ( not(eof(fichero)) AND (i<ulthora) ) do begin
i := i+1;
readln(fichero, medidas[i]);
end;
*)
while ( not(eof(fichero)) AND (i<ulthora) ) do begin
readln(fichero, medidas[i]);
i := i+1;
end;

close(fichero);
End;

(* Función que presenta menú y devuleve opción elegida *)


Function Menu: Integer;
Var
opc: integer;
Begin
repeat
writeln('Centro de control de medidas atmosféricas');
writeln('-----------------------------------------');

writeln;
writeln(' 1. Lectura de datos');
writeln(' 2. Presentación de medidas');
writeln(' 3. Cálculo de media, maximos y minimos');

writeln(' 5. Lectura de datos de fichero');


writeln(' 6. Guardar datos en fichero');
writeln;
writeln(' 9. Salir');
write(' Opción: ');
readln(opc);
until ( (opc>=1 and opc <=4) or (opc=9) );
Menu := opc;
End;

(*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!*)
(*!!!!!!!!!!!!!!!! PROGRAMA principal
!!!!!!!!!!!!!!!!!!!!!!!!!!!*)
(*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!*)
begin
repeat
opc := Menu;
case opc of
1: lectura(temperatura,'Temperatura' );
2: escritura(temperatura,'Temperatura' );
3: resultados(temperatura, 'Temperatura');
5: begin
write('Introduca el nombre del fichero de
datos: ');
readln(nombre);
lee_fichero(nombre, temperatura);
end;
6: begin
write('Introduca el nombre del
fichero de datos: ');
readln(nombre);
graba_fichero(nombre, temperatura);
end;
end;
until (opc=9);
End.
Anexo: útiles para programar en Pascal

• Editor de texto El alumno deberá codificar los programas utilizando un editor


de texto. Se recomienda utilizar el editor Notepad++. La última versión puede
descargarse desde [Link] para diversos sistemas
operativos.

• Compilador Tras la codificación del programa deberá compilar, depurar y probar los
programas (repitiendo estos pasos tantas veces como sea necesario hasta conseguir el
código correcto). Se recomienda utilizar el compilador freePascal. La última versión del
compilador puede descargarse desde [Link] para diversos
sistemas operativos.

Método de trabajo: enlace donde se explican los pasos para editar un programa.

Para más información y ejemplos del método de trabajo puede consultar el documento
guía para la depuración de código

Anexo: Ampliación de útiles para programar en Pascal. Compilador de


libre distribución

La configuración e instalación del entorno integrado Dev-Pascal la encontará en el siguiente


enlace:

• Entorno integrado de desarrollo (Editor y Compilador).

• Enlace a Dev-Pascal.

Otros compiladores Pascal

o GNU Pascal: [Link]


Otro compilador gratuito del grupo GNU.
o Hispascal: [Link]
Proyecto para traducir el Pascal a Español. Está un desarrollo muy
temprano.

También podría gustarte