Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Curso de Inicio A La Programacion (PASCAL)

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 118

Este curso de Introducción a la Programación abarca los conceptos básicos de

la programación de ordenadores bajo los paradigmas estructurado y modular: tipos


de datos, expresiones, estructuras de control, estructuras de datos y
subprogramas.

Pretende que, tras su superación, el alumno adquiera una visión global de la


programación que le permita abordar esta tarea sobre cualquier otro lenguaje de
programación con un esfuerzo moderado.

Para ello, además de desarrollar los conceptos fundamentales de un lenguaje de


programación, se insistirá en la necesidad de respetar las normas de
la programación estructurada, y se intentará que el alumno adopte una
visión modular a la hora de enfrentarse a la resolución de problemas.

Aunque los conceptos son genéricos y extensibles a otros lenguajes de


programación, este curso se basará en el lenguaje de programación Pascal, el más
recomendado desde un punto de vista didáctico para iniciarse en la programación
de ordenadores. El paso a otro lenguaje de programación no orientado a objetos,
como C, no debería suponer demasiado esfuerzo.

Al mismo tiempo este curso es un buen punto de partida para la Programación


Orientada a Objetos (POO), puesto que todos los conceptos y técnicas que se
estudian en él forman parte de esta.

El curso está dirigido a personas con conocimientos básicos de informática a nivel


de usuario, pero sin conocimientos previos de programación, por lo que constituye
el punto de entrada al apasionante mundo de la programación de ordenadores..

Cada vez que termine uno de los temas deberá realizar los ejercicios asociados que
se encuentran en el apartado Actividades - Unidades del Centro Virtual de
Educación.

Los ejemplos y ejercicios se realizarán utilizando el compilador Freepascal y el


editor NotePad++. En el siguiente anexo encontrará más información.
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 EE.UU.) 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 http://www.levenez.com/lang/ 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 http://people.ku.edu/~nkinners/LangList/Extras/langlist.htm.
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.
 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.
 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:
 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.
 Lenguajes orientados al problema: como por ejemplo Prolog. En estos
lenguajes lo que se describe es el problema en sí; son de tipo
declarativo.
 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.
Este capítulo se puede seguir de forma secuencial o bien accediendo directamente
al apartado que se desee:

 Fases en el Desarrollo del Software


 Noción de Algoritmo
 Representación de Algoritmos
 Programación modular y estructurada
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 análisis 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 proporcionan 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 programa.
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 todas 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.
Este capítulo se puede seguir de forma secuencial o bien accediendo directamente
al apartado que se desee:

 Introducción
 Estructura de un programa en Pascal
 Objetos de un programa
 Nuestro primer programa
Introducción

El lenguaje de programación Pascal surge a finales de los años 60. Su motivación


era puramente académica e intentaba desarrollar un lenguaje que reflejara los
conceptos de la programación estructurada. El lenguaje se fue propagando
rápidamente en el entorno académico e incluso originó otros lenguajes de
programación.

Pero fue a partir de los años 80 con la aparición de los compiladores de Borland
(Turbo Pascal y posteriormente Borland Pascal) cuando el lenguaje se hizo popular
en todos los ámbitos. Estos compiladores unían calidad y muy buen precio e
incorporaban herramientas y utilidades que facilitaban la creación de programas. El
fabricante Borland fue sacando al mercado versiones de dicho compilador y
finalmente con el auge del desarrollo de aplicaciones para los entornos gráficos
puso en el mercado una herramienta llamada Delphy basada en Pascal. Hoy en día
los desarrollos de Turbo Pascal se han quedado obsoletos aunque las características
y elementos introducidos son considerados un estándard "de facto", por ello es
habitual que los compiladores de Pascal señalen la compatibilidad con los
compiladores de Borland. Actualmente existen diversos compiladores de Pascal que
permite realizar todas las actividades de este curso. Se incluye un compilador
gratuito de fácil instalación y uso para plataformas Windows y se dan referencias a
otras alternativas para que el alumno tenga libertad a la hora de elegir su entorno
de trabajo. El cambio a otro compilador, entorno o sistema operativo no debe
suponer ninguna dificultad.

Hay una página muy interesante en http://www.nachocabanes.com/pascal en la


que aparecen diferentes enlaces a compiladores de Pascal, así como material
complementario y ejercicios que puede ser muy útiles para el alumno interesado en
profundizar y practicar con este lenguaje.

Por otro lado la Web tiene numerosas referencias al lenguaje, a su historia, a las
características y por supuesto a las múltiples herramientas de desarrollo que se han
ido produciendo. A modo de ejemplo la Wikipedia tanto en español como en inglés
tienen información y enlaces de
interés. http://es.wikipedia.org/wiki/Pascal_(lenguaje_de_programaci%C3%B3n) h
ttp://en.wikipedia.org/wiki/Pascal_(programming_language)
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.

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:

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 hola.pas. (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ón.htm, 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 formatoprogramas.htm, también accesible desde la sección "Materiales de
apoyo".
Este capítulo se puede seguir de forma secuencial o bien accediendo directamente
al apartado que se desee:

 Tipos Simples
 Variables y constantes
 Expresiones
 Sentencias básicas
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:

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

o El 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
elprocedimiento 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
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: ', altura:4:2);
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.
Este capítulo se puede seguir de forma secuencial o bien accediendo directamente al apartado que se
desee:

 Selectivas
 Bucles: DESDE
 Bucles: MIENTRAS
 Bucles: HASTA
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:

La representación gráfica de esta estructura, para cualquier lenguaje de programación, es la que se puede
observar en esta figura:

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:

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(cantidad:10:3); (* 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(cantidad:10:3,'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 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.

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

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 SumarDep.pas. 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".


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;
Repase el código de este ejemplo en Factorial.

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.

Sólo nos queda una estructura repetitiva por estudiar: el bucle "repetir-hasta".
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.

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.
Este capítulo se puede seguir de forma secuencial o bien accediendo directamente al apartado que se
desee:

 Introducción
 Paso de parámetros
 Funciones y procedimientos
 Ejemplos

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 capáz 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.
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 Precio.pas.

 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.
jemplo 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: ',
valorprod:0:1, ' ivaprod: ', ivaprod:0:1);

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: ', iva:0:1, ' 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: ', iva:0:1, ' 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: ', iva:0:1, ' 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: ',
valorprod:0:1, ' ivaprod: ', ivaprod:0:1);
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 preciodep.pas.

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 Intercambio.pas

 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.
Este capítulo se puede seguir de forma secuencial o bien accediendo directamente al apartado que se
desee:

 Introducción
 Definición y uso
 Tablas y cadenas de caracteres
 Tablas multidimensionales
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 tablas.pas. 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.

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 TablasLetras.pas.

Intente mejorar este programa, creando procedimientos que hagan el cálculo de ocurrencias y la
presentación por pantalla de los resultados.

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.

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.

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.
Este capítulo se puede seguir de forma secuencial o bien accediendo directamente
al apartado que se desee:

 Introducción
 Definición
 Uso de registros
 Tablas de registros
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:

alumno.nombre := 'Fermin Alerce Herranz';


alumno.edad := 48;

writeln('Nombre : ', alumno.nombre);


writeln('Edad : ', alumno.edad);

write('Peso : ');
readln(alumno.peso);

write('Altura : ');
readln(alumno.altura);

ratio = alumno.peso/alumno.altura;

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 := (per1.nombre = per2.nombre)

AND (per1.edad = per2.edad)


AND (per1.peso = per2.peso)
AND (per1.altura = per2.altura);

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(alumno.nombre);
write('Edad : ');
readln(alumno.edad);
write('Peso : ');
readln(alumno.peso);
write('Altura : ');
readln(alumno.altura);
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 : ', alumno.nombre);
writeln('Edad : ', alumno.edad);
writeln('Peso : ', alumno.peso:0:1);
writeln('Altura : ', alumno.altura:0:2);
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(alu01.datos.nombre);
write('Edad: ');
readln(alu01.datos.edad);
write('Nota Teoria: ');
readln(alu01.teoria);
write('Nota Practica: ');
readln(alu01.practica);

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].datos.nombre);

write('Edad: ');
readln(miclase[i].datos.edad);

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].datos.edad;
media := suma/TAMCLASE;
writeln('La edad media de la clase es de ', media:0:1);
End;

Puede estudiar todo el código de estos ejemplos en registros.pas.


Este capítulo se puede seguir de forma secuencial o bien accediendo directamente
al apartado que se desee:

 Introducción
 Definición
 Uso de ficheros
 Ficheros de texto
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.

nombre.ext
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, 'clase.dat');

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 "f281299.res" 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 una 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 fichC0.pas.

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, 'clase.txt');
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 fichD0.pas.
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 http://notepad-plus-
plus.org/ 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 http://www.freepascal.org/ 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: http://www.gnu-pascal.de


Otro compilador gratuito del grupo GNU.
o Hispascal: http://hispascal.sourceforge.net/
Proyecto para traducir el Pascal a Español. Está un desarrollo muy temprano.

También podría gustarte