You are on page 1of 151

Introducci on a la Programaci on.

Pascal.
Vicente Lopez
Escuela Tecnica Superior de Inform atica
Universidad Aut onoma de Madrid
( vicente.lopez@ii.uam.es )
2

Indice General
1 Esquemas Basicos 7
1.1 Ordenaci on temporal . . . . . . . . . . . . . . . . . . . . . . . 7
1.2 Componentes b asicos . . . . . . . . . . . . . . . . . . . . . . . 8
1.3 Tr aco de informaci on . . . . . . . . . . . . . . . . . . . . . . 9
2 Lenguajes 13
2.1 Procesamiento de informacion: hombre y ordenador . . . . . . 13
2.2 Formalizaci on de los lenguajes . . . . . . . . . . . . . . . . . . 15
2.3 Las maquinas de Von Neuman . . . . . . . . . . . . . . . . . . 16
2.4 Breve historia de los lenguajes . . . . . . . . . . . . . . . . . . 17
2.5 Tipos de lenguajes . . . . . . . . . . . . . . . . . . . . . . . . 20
3 Algoritmos 23
3.1 Pasos en la resolucion . . . . . . . . . . . . . . . . . . . . . . . 23
3.2 Uso m ultiple . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.3 El ejemplo de Josefo . . . . . . . . . . . . . . . . . . . . . . . 25
4 Pascal 33
4.1 Caractersticas . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.2 El programa Pascal . . . . . . . . . . . . . . . . . . . . . . . . 34
4.3 Palabras reservadas y estructuras . . . . . . . . . . . . . . . . 35
4.4 Instrucciones sencillas y compuestas . . . . . . . . . . . . . . . 37
4.5 Diagramas de sintaxis . . . . . . . . . . . . . . . . . . . . . . 38
5 Datos 39
5.1 Variables, datos y direcciones . . . . . . . . . . . . . . . . . . 39
5.2 Identicadores . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.3 Tipos de datos . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3
4

INDICE GENERAL
5.4 Constates con tipo . . . . . . . . . . . . . . . . . . . . . . . . 46
5.5 Inicializacion de los datos . . . . . . . . . . . . . . . . . . . . 46
5.6 Asignacion de las constantes . . . . . . . . . . . . . . . . . . . 46
5.7 Asignacion de los distintos tipos de variables . . . . . . . . . . 47
6 Entrada y salida 51
6.1 Dispositivos de entrada, salida y almacenamiento . . . . . . . 51
6.2 Las funciones Read y Write . . . . . . . . . . . . . . . . . . . 52
6.3 Formatos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6.4 Las funciones WriteLn y ReadLn . . . . . . . . . . . . . . . . 55
7 Acciones 59
7.1 Operaciones basicas. . . . . . . . . . . . . . . . . . . . . . . . 59
7.1.1 Operadores aritmeticos y expresiones aritmeticas. . . . 59
7.1.2 Funciones aritmeticas. . . . . . . . . . . . . . . . . . . 61
7.1.3 Aritmetica entera y real. . . . . . . . . . . . . . . . . . 62
7.1.4 Operadores logicos. . . . . . . . . . . . . . . . . . . . . 65
7.1.5 Expresiones logicas. . . . . . . . . . . . . . . . . . . . . 68
7.1.6 Manipulacion de bits. . . . . . . . . . . . . . . . . . . . 70
7.2 Sentencias de control. . . . . . . . . . . . . . . . . . . . . . . . 74
7.3 Sentencias de repeticion. . . . . . . . . . . . . . . . . . . . . . 79
7.4 Manipulacion de los datos STRING. . . . . . . . . . . . . . . 85
8 Modularidad 87
8.1 Dividir para vencer . . . . . . . . . . . . . . . . . . . . . . . . 87
8.2 Procedimientos . . . . . . . . . . . . . . . . . . . . . . . . . . 88
8.3 Funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
8.4

Ambito de denicion de las variables . . . . . . . . . . . . . . 91
8.5 Paso de valores por contenido o direccion . . . . . . . . . . . . 92
8.6 Denicion diferida . . . . . . . . . . . . . . . . . . . . . . . . . 96
8.7 Modulos y submodulos . . . . . . . . . . . . . . . . . . . . . . 97
8.8 Recursividad . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
9 Datos con estructura 103
9.1 Tipos de datos denidos por el programador . . . . . . . . . . 103
9.2 Enumeraciones . . . . . . . . . . . . . . . . . . . . . . . . . . 105
9.3 Conjuntos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
9.4 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108

INDICE GENERAL 5
9.5 Registros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
9.6 Uniones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
10 Ficheros 125
10.1 Ficheros con Tipo . . . . . . . . . . . . . . . . . . . . . . . . . 125
10.2 Procesamiento secuencial y aleatorio . . . . . . . . . . . . . . 131
10.3 Ficheros de Texto . . . . . . . . . . . . . . . . . . . . . . . . . 136
11 Punteros 141
11.1 Contenidos, direcciones e identicadores . . . . . . . . . . . . 141
11.2 Punteros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
11.3 Asignacion dinamica de memoria. . . . . . . . . . . . . . . . . 145
11.4 Declaraciones recursivas de tipos de datos . . . . . . . . . . . 147
6

INDICE GENERAL
Captulo 1
Esquemas basicos del
ordenador
1.1 Ordenaci on temporal
Un ordenador es una maquina dise nada para el procesamiento autom atico
de informaci on.
El esquema mas sencillo de un ordenador actual es el siguiente:
Entrada
Computadora
Salida
- -
Se denominan dispositivos de entrada a todos aquellos que hacen posible
la captura de los datos necesarios para realizar las tareas encomendadas al
ordenador. Ejemplos comunes de dispositivos de entrada son los teclados, las
tarjetas perforada, y los ratones, pero tambien lo son los escaners, microfonos,
terminales TRC (Tubos de Rayos Catodicos),...
Se denominan dispositivos de salida a todos aquellos que hacen posible
la comunicacion de los resultados de las tareas realizadas por el ordenador.
Ejemplos comunes de dispositivos de salida son los terminales TRC, impre-
7
8 CAP

ITULO 1. ESQUEMAS B

ASICOS
soras, y plotters, pero tambien lo son altavoces, actuadores mecanicos,...
Es fundamental en un computador la ordenaci on temporal de sus opera-
ciones:
Entrada
Computadora
Salida
- -
-
Tiempo
y los componentes se denen exclusivamente a partir de la secuencia de ope-
raciones realizadas.
1.2 Componentes basicos
Globalmente a los dispositivos de entrada y salida se les denomina perifericos.
Los dispositivos de almacenamiento de informaci on como discos, diskettes,
cintas,..., tambien son perifericos que son dispositivos de entrada o salida
seg un se grabe o se lea la informaci on.
A los componentes fsicos del ordenador se le denomina Hardware y a la
informaci on que dirige la realizacion de las tareas se le denomina Software.
El ordenador, aparte de los perifericos, consta de dos componentes prin-
cipales: Unidad de memoria y unidad central de procesos.
Ordenador
Unidad de
memoria
Unidad
central de
procesos
La unidad de memoria esta formada por cientos, miles o millones de
celdas de memoria en las que se puede almacenar informacion y que
estan identicadas por su direccion (en el sentido postal).

u u u
A 2 4 1 J 3 3
1 2 3 4 5 6 7
1.3. TR

AFICO DE INFORMACI

ON 9
Al contenido de la informaci on en general se accede por la direccion de
la celda. El contenido tambien puede ser la direccion de una celda con
lo que es posible almacenar en memoria la instrucciones que se han de
realizar incluyendo el acceso a la informaci on de las celdas.
La unidad central de procesamiento (CPU) dirige y controla el procesa-
miento de informacion que realiza el ordenador y consta de dos partes:
la unidad de control y la unidad aritmetico logica.
unidad de
memoria
unidad
de
control
unidad
aritmetico

logica
?
6
-

La unidad de control busca, obtiene, y ejecuta las instrucciones de


los programas almacenadas en la memoria. Cuando las instrucciones
indican la realizaci on de operaciones aritmeticas (+, ,... ) o logicas (
, , ...) estas se derivan para ser realizadas en la unidad aritmetico
logica.
1.3 Traco de informaci on
Vamos a ver de forma simplicada las acciones a las que da lugar en un
ordenador las instrucciones de un programa. Es fundamental comprender lo
inexcusable de la secuencialidad temporal de la instrucciones suministradas
al ordenador.
Como ejemplo vamos a considerar esta porcion de programa:
{1} a := 3;
{2} b := 5;
{3} c := a + b;
{4} c := c + 2;
{5} if (c > 9) then writeln(c);
10 CAP

ITULO 1. ESQUEMAS B

ASICOS
y consideraremos un modelo muy simplicado de un ordenador. Este modelo
dispone de una U.C.P., con unidad de control y aritmetico logica, y una
peque na memoria con 64 posiciones.
Se reservan las posiciones de la 1 a la 50 para almacenar los programas
que luego se ejecutaran y las posiciones 51, 52, 53, ... se utilizan para datos
intermedios.
En nuestro modelo se inicializan todos los datos a cero al empezar la
ejecucion del programa y cuando la U.C.P. va a empezar a ejecutar la primera
instruccion las posiciones 51, 52 y 53 contienen un 0. En esas posiciones se
almacenar an los valores de las variables a,b, y c, respectivamente,
0 0 0
51 52 53
La primera instruccion del programa
a := 3;
indica a la U.C. que en la posicion 51 de memoria ha de almacenarse el
n umero entero 3.
3 0 0
51 52 53
La segunda,
b := 5;
que en 52 almacene un 5,
3 5 0
51 52 53
y en la tercera, la U.C. realiza las siguientes acciones: obtiene los n umeros
almacenados en 51 y 52, los enva a la U.A.L. para ser sumados y el resultado
que devuelve se almacena en 53.
3 5 8
51 52 53
1.3. TR

AFICO DE INFORMACI

ON 11
En la cuarta instruccion obtiene el n umero almacenado en 53 y lo enva a
la U.A.L. junto con el 2 para ser sumados. El resultado devuelto lo almacena
de nuevo en 53.
3 5 10
51 52 53
La quinta instruccion implica que la U.C. obtiene el n umero almacenado
en 53 y lo enva junto con el 9 a la U.A.L. para ser comparados. Como
de la comparaci on la U.A.L. devuelve que es cierto, se enva al periferico
correspondiente la orden de sacar al exterior el contenido de la memoria 53.
12 CAP

ITULO 1. ESQUEMAS B

ASICOS
Captulo 2
Lenguajes de programacion
2.1 Procesamiento de informaci on: hombre y
ordenador
La informacion que puede procesar un ordenador es distinta a la que puede
procesar un humano. A un suponiendo que el procesamiento de informaci on
que realiza el cerebro humano es comparable al que realiza un ordenador,
la diferencia de dise no entre ambos explicara la incompatibilidad. Para el
humano resulta comodo expresar y pensar conceptos abstractos. La frase
Sumar dos n umeros evoca claramente un operacion general que dentro del
formalismo matematico carece de ambig uedad:
z = x + y .
Es equivalente el valor de la variable z a la suma de los valores
de las variables x e y.
El modo en que esta frase puede traducirse en una orden precisa para que la
realice un ordenador ha cambiado con el tiempo seg un variaban los dise nos de
los ordenadores. Primitivamente en ordenadores como el MARK I se trataba
de una secuencia de tripletes de perforaciones en un cinta. Hoy en da se
trata de las secuencias de ceros y unos del codigo binario. En el futuro los
programas podran parecerse a los pentagramas de m usica actuales.
Una lectura parcial de la expresion matematica anterior puede ser la
siguiente:
13
14 CAP

ITULO 2. LENGUAJES
Un valor particular de la variable z se obtiene sumando los valores
de las variables x e y.
En el lenguaje PASCAL la suma de dos n umeros correspondiente a esta
interpretaci on se expresa con la instruccion
z := x + y ;
con una sintaxis muy pr oxima a la expresion matem atica, si bien su semantica
es distinta pues ha de entenderse del siguiente modo:
El valor almacenado en la memoria identicada con el nombre x
y el valor almacenado en la memoria identicada con el nombre y,
han de sumarse almacenando el resultado en el lugar de memoria
identicado por el nombre z.
Sin embargo, la informaci on que ha de recibir la Unidad Central de Pro-
ceso de un ordenador para realizar esta operacion puede ser:
0010 0000 0000 0100
0100 0000 0000 0101
0011 0000 0000 0110
lo que en una lenguaje que establece un compromiso entre ordenador y hom-
bre corresponde a
X Y Z

LOAD X
ADD Y
STORE Z
Este lenguaje se denomina Ensamblador (Assembler) y casi corresponde a
una traducci on de la secuencia de ceros y unos en palabras mas faciles de
recordar. Se suele hablar de lenguajes de programaci on de bajo y alto nivel,
seg un se acerquen a lenguaje natural de los humanos. El ensamblador es un
2.2. FORMALIZACI

ON DE LOS LENGUAJES 15
lenguaje de programaci on de bajo nivel y el PASCAL es un lenguaje
de programaci on de alto nivel. A la secuencia binaria que acepta la UCP
del ordenador se le denomina lenguaje m aquina.
La desventaja obvia de un lenguaje de bajo nivel es lo costoso que resulta
la programaci on de un ordenador con el. A medida que un lenguaje se acerca
mas al lenguaje natural, mas sencillo es programar con el y mas accesible a
personas no especializadas. Pero existe otra desventaja: los lenguajes de
bajo nivel dependen del ordenador. Dado que se han de ce nir al dise no
logico del ordenador, un lenguaje ensamblador solo es v alido para familias
de ordenadores con el mismo dise no logico.
2.2 Formalizaci on de los lenguajes
Los lenguajes de alto nivel que vamos a estudiar en este curso son el resultado
de investigaciones realizadas desde dos enfoques distintos. Por una parte, un
lenguaje de programaci on es un caso particular de un lenguaje formal; por
otra, una solucion al problema de ingeniera que surge en la construcci on de
maquinas procesadoras de informacion.
La formalizaci on de los lenguajes es un tema de investigaci on desde los
antiguos griegos. Arist oteles (384332 A.C.) se puede considerar el padre
de la logica formal. Leibniz en el siglo XVII, y Frege en el XIX, intenta-
ron construir lenguajes formales sin la imprecision y ambig uedad de lenguaje
ordinario. Gorge Boole en 1854 proporcion o un nuevo intento de forma-
lizacion con la introduccion de smbolos, formulas y axiomas. El metodo
logico de Boole permiti o construir maquinas logicas que poda resolver au-
tom aticamente problemas logicos. Mas tarde, el espa nol Leonardo Torres
y Quevedo (18521939), entre otros dise nos mecanicos autom aticos, cons-
truy o el Ajedrecista, un automata capaz de jugar al ajedrez. A nales del
siglo XIX y en el XX, los lenguajes formales se investigaron con el intento
de formalizar las matematicas de un modo similar a como Euclides haba
formalizado la geometra. Las ideas fundamentales de Russel, Whitehead,
Hilbert, Church, y nalmente Goedel, permitieron establecer la imposibili-
dad de ese proyecto. Turing y Post en 1936 introdujeron un formalismo de
manipulaci on de smbolos ( la denominada maquina de Turing ) con el que se
puede realizar cualquier computo que hasta ahora podemos imaginar. Esta
fue una va de comunicacion entre los problemas formales de la computaci on
y de la matem atica. La union permitio demostrar que no existe ninguna
16 CAP

ITULO 2. LENGUAJES
maquina de Turing que pueda reconocer si una sentencia es o no un teore-
ma de un sistema logico formal; pero tambien permitio demostrar que si un
calculo puede explicitarse sin ambig uedad en lenguaje natural, con ayuda
de smbolos matematicos, es siempre posible programar un ordenador digital
capaz de realizar el calculo, siempre que la capacidad de almacenamiento de
informaci on sea la adecuada.
Desde el punto de vista de la ingeniera, los progresos en lenguajes de pro-
gramaci on han sido paralelos a los dise nos de los nuevos ordenadores. Babba-
ge ya escribio programas para sus maquinas, pero los desarrollos importantes
tuvieron lugar, igual que en los ordenadores, alrededor de la segunda guerra
mundial. Fue en esa epoca (justo despues de nalizada la guerra) cuando
Zuse publico su libro Calculo y programaci on. En el aparece por primera vez
el concepto de operaci on de asignaci on. Zuse se planteo el problema siguien-
te: la expresion z = z + 1 es incorrecta para signicar El nuevo valor de z
se obtiene sumando 1 al antiguo , e introdujo la expresion z + 1 z. Esta
sentencia de asignaci on nunca se haba utilizado antes pues siempre se intro-
duca una nueva variable cuando se proceda a una asignacion ( por ejemplo
y = z +1). Este nuevo enfoque es fundamental puesto que el uso sistematico
de las asignaciones es lo que distingue la forma de pensar en ciencias de la
computaci on y en matem aticas.
2.3 Las maquinas de Von Neuman
Originalmente la programaci on de un ordenador era directamente la reorde-
nacion de los componentes del ordenador. La idea de producir un programa
de ordenador que se pudiera almacenarse en la memoria del ordenador se
debe a Von Neuman y apareci o en un informe que hizo sobre el ordenador
EDVAC. Von Neuman considero la posibilidad de que una palabra formada
por 32 bit fuera o bien un n umero o bien una instruccion. Una instruccion se
codicaba por un grupo de bits adyacentes y considero sumas, multiplicacio-
nes, transferencia de contenidos de memoria a registros, test, e instrucciones
de bifurcacion. As, un programa consistira en una secuencia de palabras en
forma binaria.
Necesidades practicas muy obvias llevaron a la utilizacion de mnemotecnicos
para programar las instrucciones, y posteriormente otro programador tra-
duca los mnemotecnicos a lenguaje maquina. El paso siguiente deba ser
conseguir que fuera el ordenador el que tradujera esas codicaciones y tam-
2.4. BREVE HISTORIA DE LOS LENGUAJES 17
bien lograr que ciertos codigos correspondieran a mas de una instruccion
elemental del ordenador. Al principio de los a nos cincuenta se empezaron a
construir estos Decodicadores o Ensambladores.
El objetivo de los ingenieros que trabajaban en el dise no de los ordena-
dores era conseguir que el ordenador aceptara instrucciones con un formato
similar al matematico, puesto que en aquella epoca la mayora de la aplica-
ciones giraban alrededor de calculos complejos. Para lograr esto fue necesario
un cambio radical en el enfoque de la operacion de un ordenador.
Datos
ordenador
Programa
ordenador
Programa

Resultado
El ordenador deba considerarse como un procesador de informaci on ca-
paz de transformar un programa escrito en un lenguaje de alto nivel en un
programa en lenguaje maquina. A su vez, deba programarse el compilador
capaz de realizar esta transformaci on.
2.4 Breve historia de los lenguajes
En los a nos 50 se realizaron varios compiladores primitivos y fue en 1957
cuando aparecio el primer compilador de FORTRAN. El compilador de FOR-
TRAN (FORmula TRANslator) estaba dise nado para traducir a lenguaje
maquina expresiones y operaciones matem atica, e incluso permita la mani-
pulacion de matrices. La aparici on del FORTRAN fue un gran cambio para
18 CAP

ITULO 2. LENGUAJES
los programadores que no todos aceptaron de buen grado. No les gustaba
que sus programas fueran tratados por el ordenador como meros datos, y ar-
gumentaban que el codigo maquina generado por el compilador nunca podra
ser tan eciente como el escrito por ellos directamente. Esto no era general-
mente as, puesto que el FORTRAN no fue dise nado pensando en crear un
lenguaje bien estructurado sino pensando en crear un traductor de expresio-
nes aritmeticas a codigo maquina muy eciente. Por ello, el dise no logico del
ordenador IBM 704 para el que fue creado casi puede deducirse del lenguaje
FORTRAN. En diferentes versiones, cada vez mas estructuradas, el lenguaje
FORTRAN se ha utilizado extensivamente desde que apareci o hasta hoy en
da, y puede considerarse el lenguaje estandard del calculo cientco.
Unos a nos despues de aparecer el FORTRAN apareci o el lenguaje AL-
GOL 60 (Algorithm Language), que fue dise nado para ser independiente del
ordenador con una gram atica bien denida. Tambien de aquella epoca es el
COBOL (Common Business Oriented Language) que se dise no para para las
manipulaciones de datos normales en aplicaciones de negocios y con un uso
mayor del lenguaje ingles en sus frases. Las versiones modernas del COBOL
siguen usandose en la actualidad y es el lenguaje estandard en aplicaciones
inform aticas bancarias. Desde entonces han aparecido diversos lenguajes de
alto nivel entre los que podemos mencionar el BASIC (Beginners Allpurpose
Symbolic Instructional Code), PL/I , APL, PASCAL, ADA, MODULA , C ,
RPG, PROLOG, LISP, ... etc. Alguno de estos lenguajes han sido dise nados
para un tipo concreto de aplicaciones. Por ejemplo, el ADA para aplica-
ciones relacionadas con defensa, o el RPG para transacciones usuales en los
bancos. La evolucion de los lenguajes de programaci on ha estado guiada por
la evoluci on de:
Los ordenadores y sus sistemas operativos.
Las aplicaciones.
Los metodos de programaci on.
Los fundamento teoricos.
La importancia dada a la estandarizaci on.
Podemos resumir la evoluci on de los lenguajes de programaci on en la siguien-
te tabla:
2.4. BREVE HISTORIA DE LOS LENGUAJES 19
periodo Inuencias Lenguajes
1950 55 Ordenadores primitivos Lenguajes ensamblador
Lenguajes experimentales
de alto nivel
1956 60 Ordenadores peque nos, FORTRAN
caros y lentos ALGOL 58 y 60
Cintas magneticas COBOL
Compiladores e interpretes LISP
Optimizaci on del codigo
1961 65 Ord. grandes y caros FORTRAN IV
Discos Magneticos COBOL 61 Extendido
Sistemas operativos ALGOL 60 Revisado
Leng. de proposito general SNOBOL
APL ( como notaci on solo)
1966 70 Ordenadores de diferentes PL/I
tama nos, velocidades, costes FORTRAN 66 (estandard)
Sistemas de almacenamiento COBOL 65 (estandard)
masivo de datos (caros) ALGOL 68
S.O. multitarea e SNOBOL4
interactivos SIMULA 67
Compil. con optimizaci on BASIC
Leng. estandard , APL/360
exibles y generales
1971 75 Micro ordenadores
Sistemas de almacenamiento PASCAL
masivo de datos peque nos COBOL 74
y baratos PL /I
Progr. estructurada
Ingeniera del software
Leng. sencillos
1976 80 Ord. baratos y potentes ADA
Sistemas distribuidos FORTRAN 77
Prog. tiemporeal PROLOG
Prog. interactiva C
Abstraccion de datos
Prog. con abilidad
y facil mantenimiento
20 CAP

ITULO 2. LENGUAJES
2.5 Tipos de lenguajes
Desde un punto de vista mas general los lenguajes se pueden clasicar en
lenguajes de procedimiento o declarativos. En los primeros, con el lenguaje se
especica paso a paso el procedimiento que ha de realizar el ordenador para
procesar la informaci on, mientras que en los segundos se declaran hechos
que han de dirigir las respuestas del ordenador. El PASCAL y el C que
estudiaremos en este curso son de procedimiento, mientras que por ejemplo
el PROLOG, es declarativo.
Una porcion de programa PROLOG es as:
. . .
hijo(X,Y) <- padre(Y,X) , varon (X).
hija(X,Y) <- padre(Y,X) , hembra (X).
abuelo(X,Z) <- padre(X,Y) , padre (Y,Z).
. . .
estableciendo relaciones logicas que determinan una base de verdades con las
que han de ser coherentes las respuestas del programa.
Exite una diferencia grande en la programaci on con un lenguaje u otro
seg un sea interpretado o compilado, si bien esta distincion puede no ser inhe-
rente al lenguaje sino a su puesta en pr actica en un determinado ordenador.
Un lenguaje es interpretado cuando la transformaci on de las instrucciones de
alto nivel a lenguaje maquina se realiza sentencia a sentencia seg un se van
ejecutando. Un lenguaje es compilado cuando esta trasformaci on se realiza
en bloque antes de que ninguna instruccion sea ejecutada. Por ejemplo, el
BASIC en general se suele interpretar y el LISP siempre. En un lenguaje
interpretado la puesta a punto de un programa ha de realizarse secuencial-
mente puesto que las distintas partes del programa no se pueden vericar
hasta que entran en ejecucion.
En el caso mas com un de lenguajes compilados, son varios los subprocesos
implicados en la transformaci on del codigo de alto nivel en instrucciones
ejecutables por la UCP.
2.5. TIPOS DE LENGUAJES 21
Programa
Leng. maquina
Codigo UCP
L. maquina

.
.
.
.
.
.
.
.
.
.
..
COMPILADOR
MONTADOR

/
/
/
/
/
/
/
/
/
/
/
/
A su vez el compilador realiza varias tareas:
vericaci on de la sintaxis
transformaci on a codigo maquina
optimizaci on
Si un programa es incorrecto sintacticamente, el compilador detectara el error
y lo comunicar a con un mensaje relacionado con la regla del lenguaje que
se ha incumplido. Normalmente, estos son los errores mas comunes y mas
faciles de detectar.
El montador (Linker) unica el codigo con el proveniente de otros sub-
programas con el que se intercambian datos. Para ello realiza una lista de los
22 CAP

ITULO 2. LENGUAJES
datos que comparten todos los programas y asigna las direcciones comunes
donde cada uno debera procesar esos datos. Esta unicacion de direcciones
sera imposible si alg un procedimiento supuestamente existente en otro sub-
programa no aparece o aparece de un modo no unvoco. Tambien sera causa
de error que alg un dato compartido por subprogramas este declarado de mo-
do distinto en cada programa. Estos errores son poco comunes y facilmente
detectable con los mensajes de error proporcionados por el montador. Sin
embargo, los errores mas comunes y mas tediosos de eliminar son aquellos
de programaci on que dan lugar a sentencias sintacticamente correctas pero
que corresponde a acciones distintas a las deseadas. Desgraciadamente solo
se detectan en la ejecucion del programa.
En la actualidad existe la posibilidad de utilizar depuradores de progra-
mas (llamados en ingles debuggers por el origen de los errores en los or-
denadores primitivos ) que permiten seguir la ejecucion paso a paso de un
programa aunque se obtenga el codigo maquina por compilaci on. Esta he-
rramienta facilita enormemente la depuraci on de los programas pues permite
conocer o modicar el valor de los datos manipulados en el programa durante
la ejecucion.
Captulo 3
Algoritmos y resolucion de
problemas con el ordenador
3.1 Pasos en la resoluci on
Vamos a analizar las caractersticas del procedimiento de resolucion de un
problema con el ordenador. La mayora de las consideraciones son validas
para problemas genericos y muy pocas son especcas de esta herramienta.
Etapas del procedimiento de resolucion:
1. An alisis del problema.
2. Realizaci on de la estrategia ideada para su soluci on.
3. Vericacion y analisis del rendimiento del procedimiento.
Cada una de estas etapas consta de varias tareas:
1. An alisis del problema.
Comprension del problema.
Pues de lo contrario podemos acabar resolviendo magistralmente
un problema distinto.
Especicacion de los datos de entrada.
23
24 CAP

ITULO 3. ALGORITMOS
Dise no del esquema del algoritmo que satisface las restricciones
del problema.
ALGORITMO: Procedimiento para resol-
ver un problema paso a paso.
ALGORITMO: Conjunto de operaciones
que secuencialmente conducen a la respuesta
a una pregunta en un n umero nito de pasos.
Especicacion del modo de proporcionar la respuesta al problema
planteado
2. Realizaci on de la estrategia ideada para su soluci on.
Captura de datos.
Generacion de las estructuras de datos adecuadas para el algorit-
mo que se va a utilizar.
Especicacion de los algoritmos.
Presentacion de los resultados.
Cuando la herramienta que se utiliza es el ordenador, la estrategia se
ha de realizar en tres pasos:
(a) DISE

NO.
(b) ESCRITURA.
(c) VERIFICACI

ON.
3. Vericaci on y analisis del rendimiento del procedimiento.
Prueba con casos sencillos.
Prueba con casos complejos.
Prueba con casos extremos.
Analisis del rendimiento en casos poco favorables y en casos tpicos.
Renamiento de los algoritmos.
Renamiento de la escritura de los algoritmos.
3.2. USO M

ULTIPLE 25
3.2 Uso m ultiple
El uso m ultiple de los procedimientos para la resolucion de problemas con
el ordenador implica que los procedimientos han de cumplir los siguientes
requisitos:
La resolucion de un mismo problema con distintos datos y en periodos
largos de tiempo obliga a:
1. Realizaci on de procedimientos muy bien vericados.
2. Realizaci on de procedimientos muy bien documentados y escritos
con un estilo claro.
La resolucion de un mismo tipo generico de problemas o variantes del
mismo, con reutilizacion de las herramientas desarrolladas, obliga a:
1. Realizaci on de procedimientos modulares.
2. Realizaci on de procedimientos muy bien documentados y escritos
con un estilo claro.
El uso del procedimiento dentro de un equipo por distintas personas
para resolver un mismo problema o variantes de el, obliga a:
1. Realizaci on de procedimientos muy bien vericados.
2. Realizaci on de procedimientos modulares.
3. Realizaci on de procedimientos muy bien documentados y escritos
con un estilo claro.
3.3 El ejemplo de Josefo
Vamos a ver el signicado de todas estas consideraciones con un ejemplo:
una variante del Problema de Josefo (Flavio Josefo, I DC):
Un grupo de personas preeren el suicidio a la esclavitud y deci-
den colocarse en crculo eligiendo siempre al siguiente como eje-
cutor y asesinando al situado despues del ejecutor. As sucesiva-
mente hasta que quede un solo ciudadano que debera suicidarse.
El problema de Josefo es conocer en que lugar ha de colocarse en
el corro para quedar el ultimo y reexionar libremente sobre la
decision colectiva.
26 CAP

ITULO 3. ALGORITMOS
Se pretende disponer de un programa en Pascal capaz de proporcionar rapidamente
la posicion privilegiada.
1. Analisis del problema.
Comprension del problema.
Es muy util empezar con un caso sencillo.

_
1
2 3
4
5
6
Especicacion de los datos de entrada.
En este caso es solo el n umero de individuos en el crculo.
Dise no del esquema del algoritmo que satisface las restricciones
del problema.
Si es posible utilizar una estructura de datos de lista circular el
algoritmo es una copia del metodo gr aco de resolver el problema.
Especicacion del modo de proporcionar la respuesta al problema
planteado
La respuesta es comunicar el n umero de orden del ultimo individuo
en el crculo.
2. Realizaci on de la estrategia ideada para su soluci on.
Captura de datos.
3.3. EL EJEMPLO DE JOSEFO 27
{ Lectura del numero de personas en el circulo }
Readln(n);
Generacion de las estructuras de datos adecuadas para el algorit-
mo que se va a utilizar.
Se dene la estructura de datos mas adecuada
{ el tipo NODO es un registro que contiene el ordinal y un }
{ enlace al siguiente nodo. Se formara una lista circular de nodos }
type enlace = ^nodo;
nodo = record
numero: integer;
siguiente: enlace
end;
var
j , n : integer;
individuo , temporal: enlace;
y se rellena
{Se construye la lista circular }
{ Se genera el nodo de cabeza y se guarda en TEMPORAL }
{ para luego poder cerrar el circulo }
new(individuo);
individuo^.numero := 1;
temporal := individuo;
{ Se generan los restantes nodos hasta completar los N nodos}
for j := 2 to N do begin
new(individuo^.siguiente);
individuo := individuo^.siguiente;
individuo^.numero := j;
end; {endfor}
{Se cierra la lista circular al apuntar con el n-esimo }
{nodo al primero }
individuo^.siguiente := temporal;
28 CAP

ITULO 3. ALGORITMOS
Especicacion de los algoritmos.
{Algoritmo de eliminacion de individuos de la lista circular}
{Mientras quede mas de un solo nodo en la lista se eliminan }
while ( individuo <> individuo^.siguiente ) do begin
{se salta al ejecutor }
individuo:= individuo^.siguiente;
{se avisaria del individuo que seria eliminado }
{ writeln (individuo^.siguiente^.numero);}
{se almacena el nodo que se va eliminar para luego liberarlo }
{de la memoria}
temporal := individuo^.siguiente;
{Se une el antecesor del nodo fiambre a su sucesor}
individuo^.siguiente := individuo^.siguiente^.siguiente;
{y la liberacion de la posicion de memoria del nodo completa la}
{ejecucion }
dispose(temporal);
end; {endwhile}
Presentacion de los resultados.
{Se comunica el orden del ultimo en el circulo }
writeln (individuo^.numero);
El programa completo es:
Program Josefo (input,output);
{ el tipo NODO es un registro que contiene el ordinal y un enlace }
{ al siguiente nodo. Se formara una lista circular de nodos }
type enlace = ^nodo;
3.3. EL EJEMPLO DE JOSEFO 29
nodo = record
numero: integer;
siguiente: enlace
end;
var
j , n : integer;
individuo , temporal: enlace;
begin { Josefo }
{ Lectura del numero de personas en el circulo }
Readln(n);
{Se construye la lista circular }
{ Se genera el nodo de cabeza y se guarda en TEMPORAL para }
{ luego poder cerrar el circulo }
new(individuo);
individuo^.numero := 1;
temporal := individuo;
{ Se generan los restantes nodos hasta completar los N nodos}
for j := 2 to N do begin
new(individuo^.siguiente);
individuo := individuo^.siguiente;
individuo^.numero := j;
end; {endfor}
{Se cierra la lista circular al apuntar con el n-esimo nodo al primero}
individuo^.siguiente := temporal;
{Algoritmo de eliminacion de individuos de la lista circular }
{Mientras quede mas de un solo nodo en la lista se eliminan }
while ( individuo <> individuo^.siguiente ) do begin
{se salta al ejecutor }
individuo:= individuo^.siguiente;
30 CAP

ITULO 3. ALGORITMOS
{se avisaria del individuo que seria eliminado }
{ writeln (individuo^.siguiente^.numero);}
{se almacena el nodo que se va eliminar para luego liberarlo }
{de la memoria}
temporal := individuo^.siguiente;
{Se une el antecesor del nodo fiambre a su sucesor}
individuo^.siguiente := individuo^.siguiente^.siguiente;
{y la liberacion de la posicion de memoria del nodo completa la}
{ejecucion }
dispose(temporal);
end; {endwhile}
{Se comunica el orden del ultimo en el circulo }
writeln (individuo^.numero);
end. { Josefo }
3. Vericaci on y analisis del rendimiento del procedimiento.
Prueba con casos sencillos.
Se probara con N = 6 para el que se conoce bien el resultado.
Prueba con casos complejos.
Se probara con N grande.
Prueba con casos extremos.
Se probara con N = 1.
Analisis del rendimiento en casos poco favorables y en casos tpicos.
En este caso el algoritmo utilizado crece linealmente con el n umero
de individuos considerado.
Renamiento de los algoritmos.
En este caso un analisis mas detallado del problema lleva a un
algoritmo mucho mas eciente y cuyo costo computacional es in-
dependiente del n umero N de elementos en el crculo:
3.3. EL EJEMPLO DE JOSEFO 31
Si se descompone N de la forma N = 2
m
+ l el ultimo elemento
que se elimina es el 2l + 1.
Renamiento de la escritura de los algoritmos.
Uso m ultiple del programa.
Vericacion.
La vericacion a menudo debe incluir pruebas para detectar el mal uso
del programa por parte de un usuario que no esta familiarizado con el
programa o con el problema.
En el programa Josefo la captura de datos de datos podra incluirse
una especicacion del dato requerido y una vericacion del valor.
{ Lectura del numero de personas en el circulo }
writeln( Teclee el n umero de elementos en el crculo );
Readln(n);
if (n <1) then begin
writeln( Ha de ser un numero mayor que cero);
Halt;
end; {endif}
Modularidad.
Documentaci on.
Claridad de estilo.
El programa Josefo si se acompa na de la adecuada documentacion
externa permite su utilizaci on para distintos datos y en tiempos futuros.
Su modicacion para variantes del mismo problema es sencilla. Ima-
ginemos que el problema se modica y se eliminan elementos saltando
cada vez M individuos en vez de 2. Aparte de la modicacion en la
entrada de datos , la modicacion del algoritmo es mnima y sencilla
de localizar:
{se salta al ejecutor }
individuo:= individuo^.siguiente;
32 CAP

ITULO 3. ALGORITMOS
se modicara a:
{se salta al ejecutor }
for j := 1 to ( M -1 ) do begin
individuo:= individuo^.siguiente;
end; {endfor}
Esta modicacion sera igual de facil para el autor original del programa
como para cualquier otro programador.
Captulo 4
Pascal y Turbo Pascal
4.1 Caractersticas
El PASCAL es un lenguaje relativamente moderno, desarrollado por Niklaus
Wirth y su grupo de Zurich en 1971. Se trata de un lenguaje de prop osito
general, esto quiere decir que se puede emplear para construir todo tipo de
aplicaciones. En la pr actica tambien quiere decir que se trata de un lenguaje
no dise nado para desarrollar ning un tipo especco de aplicaciones. Pero el
PASCAL es especialmente util para algo: para la ense nanza de buenos modos
de programaci on. El PASCAL es hoy en da el lenguaje mas usado para la
ense nanza de la programaci on por varios motivos:
Posee unas reglas sencillas de sintaxis.
Es un lenguaje muy estructurado.
Realiza una comprobaci on exhaustiva de tipos de datos.
El hecho de que tenga una estructuraci on muy marcada permite que los pro-
gramas sean faciles de leer e interpretar, y facilita la escritura de programas
del modo que hoy en da se estima correcto.
El compilador de PASCAL es relativamente sencillo de realizar, por lo
que se ha extendido a muchos tipos de plataformas, desde los ordenadores
personales a los grandes ordenadores corporativos. Cuando una aplicacion
se escribe en PASCAL estandard puede compilarse en cualquier maquina en
la que exista compilador de PASCAL , que son la mayora.
33
34 CAP

ITULO 4. PASCAL
Existen varios dialectos locales del PASCAL , entre los que se encuentra el
TURBO PASCAL , que admiten todas las instrucciones del PASCAL estan-
dard mas un subconjunto especco de instrucciones normalmente pensadas
para aumentar las capacidades del lenguaje en un ordenador particular.
El TURBO PASCAL , de la compa na Borland (Scotts Valley, Califor-
nia) es un dialecto del PASCAL que incluye ademas de las instrucciones del
PASCAL estandard una serie de instrucciones que permiten desarrollar apli-
caciones especcas para ordenadores IBM PC o IBM PS y compatibles. No
es la unica de las versiones de PASCAL existente para estos ordenadores,
pero sin duda la mas extendida y probada. En la actualidad la version 6.0 de
este lenguaje incluye ademas del compilador un entorno integrado de desa-
rrollo (IDE) que permite compilar, visualizar errores y depurar los programas
desde un mismo entorno.
4.2 El programa Pascal
Un programa PASCAL es un conjunto de instrucciones que siguen la sintaxis
y la estructura del PASCAL . La estructura generica es:
Program nombre (cheros);
. . .
declaraciones
. . .
Begin
. . .
sentencias
. . .
End.
Todo programa Pascal empieza con la palabra Program seguida de un
nombre que elige el programador para identicar el programa. A continuacion
entre parentesis se pueden indicar los cheros que contienen los datos de
entrada y salida respectivamente. Estos cheros son el input y el output
para indicar entrada desde el teclado y salida al terminal. Si se quieren
especicar estos cheros la primera lnea de un programa sera:
Program nombre (Input , Output );
4.3. PALABRAS RESERVADAS Y ESTRUCTURAS 35
y es equivalente a:
Program nombre ;
La primera lnea del programa es una instruccion PASCAL y como todas
ellas termina con el signo de puntuaci on ; .
Despues de la identicacion del programa se han de situar las instruccio-
nes declarativas del programa que sirven para especicar sin ambig uedad el
signicado de los terminos que se utilizar an en el programa. A continuacion
han de aparecer las instrucciones correspondientes al procedimiento que se
quiere realizar. Esta instrucciones estan encabezadas por Begin y terminan
con End y un punto. El programa mas peque no y mas in util que cumple las
reglas de estructuracion del PASCAL es:
Program nulo;
{ Programa ejemplo de la estructura
mas simple de un programa PASCAL }
Begin
(* No hace falta ninguna instruccion
para no hacer nada *)
End.
En la parte reservada a declaraciones no se incluye nada pues nada se
necesita declarar. Todos los smbolos que se encuentren entre los parentesis
{ } son comentarios que sirven para hacer mas legible el programa. Tambien
los smbolos compuestos (* y *) sirven para delimitar el principio y n de un
comentario. Al existir dos tipos de delimitadores de comentarios, es posible
realizar anidacion de comentarios. Por ejemplo,
{ Este es un comentario
(* sintacticamente *)
correcto en PASCAL }
4.3 Palabras reservadas y estructuras
Las palabras Program, Begin, End, Input, y Output, y otras que vere-
mos mas adelante, son identicadores que permiten al compilador PASCAL
36 CAP

ITULO 4. PASCAL
interpretar el programa y no se pueden utilizar con otros nes. Estas palabras
se suelen referir con el termino Palabras reservadas. El compilador interpreta
igual may usculas o min usculas, y por tanto se pueden usar indistintamente.
Esta libertad de eleccion debe utilizarse para aumentar la legibilidad de los
programas. Por ejemplo, podemos empezar siempre con may uscula las pa-
labras reservadas y as sera mas facil detectar las estructuras del programa.
Tambien suele escribirse todo con may usculas el nombre de las constantes
cuyo valor no puede alterarse durante el programa. La eleccion de un estilo
u otro de escritura suele variar pero lo importante es que sea uniforme a lo
largo del programa.
En la parte del programa reservada para declaraciones se incluyen diversos
tipos de declaraci on:
{1} Program nombre ;
{2} (* Este es un ejemplo de la estructura de la
{3} parte declarativa de un programa PASCAL *)
{4} Uses nombre unidades ;
{5} Const
{6} nombre constante = valor ;
. . .
{7} Type
{8} nombre tipo = def tipo ;
. . .
{9} Var
{10} nombre variable : tipo dato ;
. . .
{11} Begin
. . .
La palabra reservada Uses de la instruccion {4} se utiliza para especicar
el nombre las unidades donde se almacenan otros trozos de codigo PASCAL
que son necesarias para completar el codigo especicado en este programa.
Normalmente se trata de porciones de codigo que forman parte de una librera
de programas. En la instruccion {5} la palabra reservada Const indica
que se ha acabado la parte iniciada por Uses y se empieza la parte de
declaraci on de las constantes que aparecen en el programa. Con Type se
4.4. INSTRUCCIONES SENCILLAS Y COMPUESTAS 37
inicia la declaracion de tipos de datos denidos por el programador, y con
Var la especicacion del tipo de dato que corresponde a las variables que se
utilizan en el programa. Finalizada esta parte declarativa, empezaran las
instrucciones del procedimiento que se esta programando ({11}). Las lneas
de codigo {1} , {4} , {6} , {8} y {10} corresponden a sentencias PASCAL
y por tanto acaban con el signo de puntuacion ;. Aparte de estos tipos de
declaraci on tambien existen las de etiquetas, procedimientos y funciones.
4.4 Instrucciones sencillas y compuestas
El cuerpo de instrucciones del procedimiento esta formado por sentencias que
pueden ser sencillas o compuestas. Las sentencias sencillas acaban con ;
y las compuestas empiezan por Begin y acaban con End. Por ejemplo,
{1} If (a > 0) Then
{2} b := a * a * a ;
la sentencia {2} es sencilla y esta delimitada por la palabra reservada Then
de la construccion condicional iniciada por If, y por el punto y coma. Esta
sentencia sencilla es completamente equivalente a la compuesta especicada
entre {4} y {7}:
{3} If (a > 0) Then
{4} Begin
{5} b := a * a ;
{6} b := b * a
{7} End;
El principio de la sentencia es el Begin de {4}, y el nal el End de {7}.
La sentencia compuesta consta de dos sencillas. La especicada en {5} se
termina con la puntuaci on ; mientras que la de {6} no necesita otra -
nalizacion que el End. As mismo, la sentencia compuesta ha de nalizarse
con el ; situado despues del End en {7}. En cualquier lugar de un pro-
grama PASCAL donde puede incluirse una sentencia sencilla tambien puede
incluirse una compuesta.
38 CAP

ITULO 4. PASCAL
4.5 Diagramas de sintaxis
La forma mas escueta de representar las construcciones sintacticamente validas
del PASCAL es utilizar los diagramas de sintaxis. La especicacion de las
dos opciones que existen, sentencias sencillas o compuestas, sera as con un
diagrama de sintaxis:
/
/
/
'
'
'
'
'
'
'
'
'
_
`

Instruc. senc.
_
`

_
'
'
'
'
'
'
'
'
'

;
`
`
`
Instruccion sencilla
Begin
End
Este diagrama ha de leerse siguiendo las fechas de izquierda a derecha y
siendo valido cualquier camino en toda bifurcacion. Una construccion estara
representada por un diagrama de sintaxis cuando empezando por la izquierda
se puede salir por la derecha y cada una de las partes de la construccion co-
rresponde a las especicaciones que se encuentran en el camino. Por ejemplo,
las sentencias presentadas en los ejemplos anteriores son correctas, mientras
que la siguiente:
{4} Begin
{5} b := a * a ;
{6} b := b * a ;
{7} End;
es incorrecta. Si seguimos el diagrama nos encontramos que despues del
punto y coma, al nal de {6}, debera haber otra sentencia sencilla mientras
que existe un End.
Captulo 5
Datos
5.1 Variables, datos y direcciones
En este tema vamos a ver las instrucciones necesarias en un programa PAS-
CAL para especicar los tipos de datos que se van a manejar. Los datos se
almacenar an en la memoria del ordenador en una determinada posicion, pero
para referirnos a ellos se utilizan nombres que el programador elige libremen-
te. El lenguaje PASCAL permite utilizar comodamente una gran variedad
de tipos de datos, pero en este tema solo vamos a ver los mas sencillos.
PI 7161
3.14159
-
6
nombre
contenido
direccion
Las primeras instrucciones de un programa han de ser las que indican los
tipos de datos que se van a utilizar. Cuando un nombre se utiliza para un
dato que no va a modicarse se trata de un a constante. Si por el contrario
se permite que el contenido de las posiciones de memoria referidas por un
determinado nombre varen durante la ejecucion del programa, se trata de
una variable.
Program Uno;
Const
39
40 CAP

ITULO 5. DATOS
PI = 3.14159;
UNIDADES = radianes ;
Var
n , m : Integer;
z : Real;
Begin
. . . .
Este es un comienzo v alido de programa en el que se especican datos y
variables que se van a utilizar. La seccion donde se agrupan las deniciones
de constantes se encabeza con el indicativo Const, la seccion de variables con
Var, y ambas han de preceder el indicativo Begin que anuncia el comienzo
de las instrucciones del programa que van a manipular los datos. En el
apartado de constantes para asignar el valor se utiliza el operador = , en
lugar del operador normal de asignaci on := .
5.2 Identicadores
Los nombres que se pueden utilizar para referirse tanto a las variables como
a las constantes son todos aquellos que no establezcan conicto con las pala-
bras reservadas en PASCAL para especicar datos o acciones. NO pueden
utilizarse:
Palabras reservadas
Begin 1.23E2 123 While Cos
Palabras que empiecen por n umeros
1YA 2ABC
Palabras en las que se encuentre alguno de los indicadores de operadores
PASCAL
x+y precio/calidad signo*valor
Palabras separadas por blancos.
5.3. TIPOS DE DATOS 41
Se pueden utilizar indistintamente may usculas o min usculas pero el com-
pilador de PASCAL no las distinguir a.
Son validos nombres como
a364b46 coco xxx2
pero se deben utilizar nombre que tengan relaci on con el dato que van a
contener. Por ejemplo,
angulo lado vertice CaraOpuesta
Algunos compiladores de PASCAL solo admiten n umeros y letras en la com-
posicion del nombre de datos y variables. El TURBO PASCAL tambien
admite otros caracteres. Por ejemplo, permite
Cara_Opuesta Nombre_Compuesto
En el ejemplo Uno podemos ver que el tipo de datos que van a contener
las constantes se especica por los valores que se asignan.
Program Uno;
Const
PI = 3.14159;
UNIDADES = radianes ;
Var
n , m : Integer;
z : Real;
Begin
. . . .
Sin embargo, el tipo de las variables ha de indicarse explcitamente con indi-
cadores PASCAL tales como Integer, o Real. Estos se reeren a dos tipos
de datos numericos entre los posibles en PASCAL .
5.3 Tipos de datos
Los tipos de datos sencillos son:
1. Numericos.
N umeros enteros:
42 CAP

ITULO 5. DATOS
Integer
Byte
ShortInt
Word
LongInt
N umeros reales:
Real
Double
Single
Extended
2. Caracteres y alfanumericos.
Char
String
3. Valores de la logica de Boole
Boolean
Integer
Es el tipo de variable que se usa para n umeros enteros ( sin parte
decimal ) con signo. Para una variable Integer se reservan dos bytes
(16 bits) en memoria y puede almacenar n umeros enteros en el rango
entre
32, 768(2
15
) y + 32, 767(2
15
1)
Es el tipo de variable utilizado normalmente para las operaciones aritmeticas
entre enteros.
LongInt
Para aquellos casos en los que es necesario utilizar enteros que exceden
el lmite aceptado por el tipo Integer, existe el tipo LongInt para el
que se reservan 4 bytes en memoria. Con una variable de tipo LongInt
se pueden referenciar n umeros enteros con signo en el rango entre
2, 147, 483, 648(2
31
) y +2, 147, 483, 647(2
31
1) .
5.3. TIPOS DE DATOS 43
Word
En este tipo de datos se pueden almacenar enteros sin signo. Al igual
que para el tipo Integer, para el tipo Word se reservan 2 bytes en
memoria y puede admitir n umeros enteros entre 0 y 65, 535.
Byte
En PASCAL es posible utilizar un tipo de dato llamado Byte, para el
que , como su nombre indica, solo se reserva 1 byte de memoria. En
las variables tipo Byte se pueden almacenar n umeros enteros sin signo
y por tanto tendran que estar limitados entre 0 y 255(2
8
1).
Real.
Para almacenar n umeros reales ( con parte decimal ) o enteros que
excedan el lmite permitido por LongInt , se ha de utilizar el tipo de
variable Real . A este tipo de datos tambien se le conoce con el nombre
de coma otante por el uso que se hace de los 6 bytes que se reservan
en memoria para este tipo de datos. Con los 6 bytes y una forma de
representar el n umero algo rebuscada que estudiaremos con los erro-
res numericos, se pueden almacenar n umeros entre 2, 910
39
y 1, 710
38
tanto positivos como negativos. Debido a la representaci on interna
utilizada, se almacenan con igual precision (7 u 8 cifras signicativas)
todos los n umeros reales en el rango permitido.
Las operaciones con n umeros en la representacion en coma otante
son mucho mas lentas que entre n umeros enteros representados direc-
tamente con su valor en base 2. Un coprocesador matem atico (como
los 80X87) se dedica especcamente a estas operaciones. El TURBO
PASCAL permite una coleccion de datos para tratar ecientemente con
n umeros reales cuando se dispone del coprocesador matematico. Cuan-
do no se dispone de el, las operaciones se pueden emular por software
aunque son mas lentas. Esta coleccion de tipos de datos son:
Single
El tipo de datos Single es un Real mas corto (4 bytes) con el
mismo rango de variaci on que el Real , pero con menos cifras
signicativas.
Double
44 CAP

ITULO 5. DATOS
Se trata de un Real largo (8 bytes) que acepta n umeros reales
entre 10
308
y 10
308
y opera con 15 o 16 cifras signicativas.
Extended
Esta es la eleccion si el tiempo de calculo no es problema y prima
la precision. Se trata de un tipo de dato para el que se reservan
10 bytes en memoria y puede almacenar n umeros reales desde
3.410
4932
y 1.110
4932
. Se pueden distinguir n umeros que tienen
19 0 20 dgitos iguales.
Boolean
Los valores que puede tomar una variable logica, dentro de la logica
Booleana (George Boole, Inglaterra 1815 1864), son Verdadero o Fal-
so. En PASCAL se suelen utilizar este tipo de variables para almacenar
el resultado comparaciones o el establecimiento de condiciones. Su dos
valores posibles son True y False.
Var
mayor , menor : Boolean;
{ ...... }
begin
{ ...... }
mayor := True;
menor := False;
{ ...... }
Char
Para un dato del tipo Char se reserva un solo byte de memoria. En
ese byte se puede almacenar informaci on de un car acter alfanumerico.
Si bien en la memoria del ordenador se esta almacenando un n umero
entero entre 0 y 255, este n umero no puede entrar a formar parte de
operaciones aritmeticas con n umeros enteros pues se entiende que se
trata de un caracter ASCII. El numero almacenado es el ordinal del
caracter en la tabla ASCII.
String
Cuando se quieren manipular grupos de caracteres ordenados, como
por ejemplo en texto, se dispone del tipo de datos String. En una
5.3. TIPOS DE DATOS 45
variable del tipo String se pueden almacenar entre 1 y 255 caracteres
de los que se almacenan en una variable var . Por tanto el numero de
bytes que se reservan para este tipo de datos dependera de caso y el
programador tendr a que especicarlo.
En este ejemplo se puede ver como se realiza la especicacion:
Program Dos;
Const
Lugar = modulo;
Var
facultad : Char;
modulo , clase : String[6];
begin
{ ...... }
facultad := C;
modulo := -XVI;
clase := facultad + modulo;
writeln( Sera en el ,Lugar, ,clase);
{ ....... }
end.
El lugar que ocupa en memoria una variable String[N], no son N bytes,
sino N+1. Esto es debido a que en el primer byte se almacena el n umero
actual de componentes. En el ejemplo anterior, el espacio reservado
para modulo se distribuye:
4 - X V I % A
Los compiladores PASCAL no inicializan las variables al principio de la
ejecucion del programa, por lo que en los espacios de memoria reserva-
dos y no rellenados se puede encontrar cualquier tipo de informaci on.
Si bien se necesita un byte de almacenamiento extra por String, el
procesamiento de estas cadenas de caracteres puede ser muy eciente.
46 CAP

ITULO 5. DATOS
5.4 Constates con tipo
Cuando se quiere utilizar en un programa una variable pero su valor se quiere
asignar antes de cualquier operacion, se puede hacer uso de las Constates
con tipo. Se trata mas que de verdaderas constantes, de variables con
asignaci on inicial de valor. El contenido en memoria de una constante con
tipo puede modicarse con las instrucciones del programa. Su sintaxis es
una mezcla de la asignaci on de tipo de las variables y de la denicion de
constantes. El programa Tres produce el mismo resultado que Dos.
Program Tres;
Const
lugar : String[13] = modulo;
begin
{ ...... }
lugar := lugar + C+ -XVI;
writeln( Sera en el ,lugar);
{ ....... }
end.
5.5 Inicializaci on de los datos
Dado que en PASCAL no se inicializan a cero , falso, o caracteres blancos, las
variables cuando se dene su tipo, hay que tener precaucion de no utilizar el
contenido de posiciones de memoria reservadas y no asignadas. Una medida
tajante es inicializar todas las variables.
5.6 Asignaci on de las constantes
Cuando se asigna el valor a una constante no se identica explcitamente el
tipo de dato del que se trata. Esta identicaci on se realiza por el contenido del
termino a la derecha del operador =. Tanto en la asignaci on de constantes,
como en la de variables en el cuerpo del programa, el compilador decide el
espacio de memoria que ha de reservar para cada valor por el modo en que
esta escrito.
5.7. ASIGNACI

ON DE LOS DISTINTOS TIPOS DE VARIABLES 47


Const
lugar = modulo;
En este caso, lugar es una constante del tipo String por que le asigna un
valor que es un conjunto de caracteres separados por comas.
Const
facultad = C;
Cuando entre comas se sit ua un solo car acter, se trata del valor de una
constante Char . Tambien es sencillo reconocer los datos Boolean porque
se les asigna el indicador True o False . En el caso de los n umeros, la
distincion se realiza entre enteros y reales. Para las constantes asignadas
con n umeros reales, el compilador elige el tipo Real, y para los enteros el
Integer. La distincion entre n umeros enteros y reales se hace por existencia
de punto decimal en el valor. Para los n umeros reales existe tambien la
posibilidad de notacion cientca.
Const
Pi = 3.14159;
PiMedios = 1570.8e-3;
PiGrados = 180 ;
El compilador PASCAL interpreta que PiGrados es una constante Integer
, y las otras dos constantes del tipo Real .
5.7 Asignaci on de los distintos tipos de va-
riables
En el cuerpo del programa se suelen asignar valores a variables. En este
caso, a partir de las instrucciones de la seccion destinada a la identicacion
del tipo de variables, se reserva el espacio adecuado de memoria para cada
variable. Por tanto, es importante que en el lado derecho del operador de
asignaci on (:=) se encuentre un valor correspondiente al tipo de variable de
lado izquierdo.
Program Cuatro;
const
Calle = Paloma Blanca ;
48 CAP

ITULO 5. DATOS
Direccion = 11 ;
Puerta = B ;
var
nombre : String[40];
numero : Integer;
letra : Char;
begin
{ Asignaciones incorrectas }
(* Asignaciones ilegales
{1} nombre := Direccion;
{2} numero := Calle;
{3} numero := Puerta;
{4} letra := Calle;
{5} letra := Direccion ;
{6} nombre := 98;
{7} numero := Paloma Negra ;
{8} numero := A ;
{9} letra := Paloma Negra ;
{10} letra := 97 ;
*)
(* Asignaciones legales *)
{11} nombre := Puerta;
{12} nombre := C;
{ Asignaciones correctas }
{13} nombre := Calle;
{14} nombre := Paloma Negra ;
{15} numero := Direccion;
{16} numero := 97;
{17} letra := Puerta;
{18} letra := A;
end.
Las instrucciones {11} y {12} son incorrectas porque asignan a una variable
del tipo String una constante del tipo Char. No obstante, estas instruc-
ciones no dan lugar a error en PASCAL porque el compilador interpreta las
variables Char como un subconjunto de las String (El espacio reservado en
5.7. ASIGNACI

ON DE LOS DISTINTOS TIPOS DE VARIABLES 49


memoria para un String acomoda perfectamente un Char ).
En el caso de valores numericos,
Program Cinco;
const
Doce = 12.0;
Once = 11;
var
i : Integer;
z : Real;
begin
{ Asignaciones incorrectas }
(* Asignaciones ilegales
{1} i := Doce ;
{2} i := 24 ;
*)
(* Asignaciones legales *)
{3} z := Once ;
{4} z := 22 ;
{ Asignaciones correctas }
{5} i := Once ;
{6} i := 24 ;
{7} z := Doce ;
{8} z := 22. ;
end.
el compilador interpreta los Integer como un subconjunto de los Real.
Para los efectos sintacticos, cualquier valor numerico ( o dato alfanumerico)
en el cuerpo del programa se considera igual que situado en el lado derecho
en una asignaci on de constante del tipo correspondiente.
50 CAP

ITULO 5. DATOS
Captulo 6
Intercambio basico de datos y
resultados
6.1 Dispositivos de entrada, salida y almace-
namiento
La comunicacion entre el ordenador y el usuario se realiza a traves de los
dispositivos denominados de entradasalida (E/S , I/O). Todo programa de
ordenador se comunica con el exterior. Algunas veces la comunicacion se
realiza directamente con el usuario a traves del teclado y el terminal TRC.
Otras, se utilizan intermediarios como son los dispositivos de almacenamiento
de informacion (discos, diskettes,...). En este ultimo caso, el programa lee los
datos del archivo donde se guardan y tambien puede escribir los resultados
en el archivo que se halla indicado para el almacenamiento.
Para cada problema concreto habra un modo optimo de comunicacion
con el ordenador.
En aquellos casos en los que se utilicen exclusivamente dispositivos de
almacenamiento intermedio de informaci on, se estar a descartando la posi-
bilidad de un proceso interactivo, es decir, la posibilidad de que el usuario
pueda utilizar la informacion generada por el ordenador para proporcionar
nuevos datos.
En este tema, se veran los modos basicos de intercambio de informaci on
con el ordenador, dirigido desde un Programa PASCAL . Supondremos que
los dispositivos que se utilizan para entrada y salida de datos son el tecla-
do y el terminal TRC, respectivamente. En muchos sistemas operativos el
51
52 CAP

ITULO 6. ENTRADA Y SALIDA


redireccionamiento necesario para utilizar archivos es trivial.
Las instrucciones de E/S se especican dentro del cuerpo principal del
Programa PASCAL . Se trata de una accion que permite transmitir informa-
cion desde el exterior a la memoria del ordenador, y viceversa. Obviamente,
el resultado de una instruccion de salida depende del contenido de la memoria
del ordenador en ese instante.
6.2 Las funciones Read y Write
Para la entrada de datos, PASCAL dispone del procedimiento basico Read(),
y para la salida de Write().
Program Uno;
{ Cuadrado de un numero entero }
Var
base , resultado : integer;
Begin
{1} Read(base);
{2} resultado := base * base;
{3} Write(resultado);
End.
La instruccion {1} del programa Uno asigna a la variable base el valor
entero suministrado por el usuario. La introduccion del dato se puede rea-
lizar tecleando el n umero deseado y pulsando despues la tecla de retorno
de carro. El procedimiento Read(argumento) asigna a la variable argu-
mento el conjunto de caracteres que se teclean antes del retorno de carro,
convenientemente interpretados de acuerdo con el tipo de dato de la variable
argumento.
La instruccion {3} escribe en la pantalla del terminal el resultado de
elevar al cuadrado el dato.
Si se teclea el n umero 93, se obtiene en pantalla 8649, pero si se teclea
93.0 el programa emitira un mensaje de error. Esto es debido a que el
procedimiento Read incluye una vericacion de que el dato suministrado
corresponde al tipo de dato denido para la variable.
El modo en que se han de suministrar los datos al programa para que
sean aceptados por el procedimiento Read() es muy parecido al modo en
6.2. LAS FUNCIONES READ Y WRITE 53
que se han de asignar los valores de las constantes dentro de un Programa
PASCAL . De hecho, es igual salvo dos excepciones:
Los datos de las variables Char y String NO deben ir entre comillas
( ).
Los valores de variables Boolean no pueden leerse.
Tanto Read() como Write() admiten m ultiples argumentos, separados
por comas.
Program Dos;
Var
resultado, base , altura : Integer;
Begin
{1} Read(base,altura);
{2} resultado := base * altura;
{3} Write(Area del cuadrado: ,resultado);
End.
La instruccion {1} del programa Dos lee dos n umeros enteros que asigna a
la variable base (el primero), y a altura (el segundo).
El modo en el que el usuario puede teclear los datos de entrada es bas-
tante exible. Por ejemplo en este caso, dado que son dos n umeros enteros,
Read interpretar a un entero como una secuencia de caracteres sin ning un
blanco intermedio. Supongamos que los datos son los n umeros 27 y 31. La
secuencia de caracteres que teclea el usuario puede ser:
2 7 3 1
El procedimiento Read() interpreta los caracteres hasta el primer blanco
como integrantes del valor que se desea asignar al Integer base. Al segundo
argumento se asignar a la cadena de caracteres que antecedan al siguiente
blanco o car acter de control < CR >. Una vez nalizada la ejecucion de la
instruccion {1} estaran almacenados los valores 27 y 31 en las posiciones
de memoria asignadas a las variables base y altura, respectivamente.
El procedimiento Read() espera que se tecleen sucientes caracteres para
poder asignar valores a los argumentos de Read, y los caracteres de control
< CR > que se tecleen antes de cumplirse esta condicion son irrelevantes. Por
54 CAP

ITULO 6. ENTRADA Y SALIDA


tanto, cualquiera de las dos secuencias siguientes de teclado son equivalentes
a la discutida antes.
2 7 3 1
2 7 3 1
El procedimiento Write escribe en el dispositivo de salida el contenido
de las constantes o las variables que se encuentran en el argumento.
Area del cuadrado : es una constante del tipo String cuyo valor
es la ordenaci on de los 19 caracteres entre las comillas .
resultado es una variable Integer, y el procedimiento Write() es-
cribe su valor: 837.
La salida del programa Dos es :
Area del cuadrado: 837
Entre ambos valores el procedimiento Write() no escribe nada, y el entero,
el TURBO PASCAL lo escribe a partir de la primera cifra signicativa. Otros
compiladores de PASCAL pueden hacerlo dejando alg un blanco a la izquierda
de la primera cifra signicativa.
6.3 Formatos
En un principio es deseable controlar exactamente el modo en el que se
escribe el valor de las variables en el dispositivo de salida. Esto puede ha-
cerse especicando el formato de escritura. En PASCAL cualquier variable o
constante que se incluya en el argumento del procedimiento Write() puede
acompa narse de una especicacion del formato de salida del siguiente modo:
nombre:n:m
donde nombre es el indicativo de la variable o constante, n es el n umero de
espacios que ha de ocupar cuando se muestra, y m el n umero de espacios
6.4. LAS FUNCIONES WRITELN Y READLN 55
que han de ocupar la parte decimal (despues del punto) cuando el tipo de
variable o constante lo permita.
Por ejemplo,
Program Tres;
var
resultado, base , altura : Integer;
Begin
{1} Read(base,altura);
{2} resultado := base * altura;
{3} Write(Area del triangulo: :40,resultado:6);
end.
dar a como resultado
Area del triangulo: 837
Los espacios que no ocupan el contenido de la variable o constante, se sit uan
a la izquierda. En el caso de tratarse de n umeros reales, si no se especica el
n umero de cifras decimales, se toma por defecto la notaci on cientca. Estos
son algunos ejemplos de escritura de un n umero real:
Write(102030.40:8 ) 1.0E+0005
Write(102030.40:10) 1.0E+0005
Write(102030.40:12) 1.020E+0005
Write(102030.40:14) 1.02030E+0005
Write(102030.40:8:1) 102030.4
Write(102030.40:10:1) 102030.4
Write(102030.40:14:2) 102030.40
6.4 Las funciones WriteLn y ReadLn
La forma que toma la representaci on de la salida externa de un Programa
PASCAL depende tambien de la ordenacion en el sentido vertical. El car acter
de control < EOL > ( n de lnea ) gobierna lo que sera el salto de carro
de una impresora. El PASCAL dispone del procedimiento Writeln() que es
equivalente al Write() salvo que despues de escribir los argumentos tambien
escribe la secuencia de control < EOL >. As, la salida del programa Cuatro
56 CAP

ITULO 6. ENTRADA Y SALIDA


Program Cuatro;
var
resultado, base , altura : Integer;
Begin
{1} Read(base,altura);
{2} resultado := base * altura;
{3} Writeln( Resultado del calculo.);
{4} Writeln(Area del triangulo: :40,resultado:6);
end.
para los mismos datos suministrados al programa Tres sera:
Resultado del calculo.
Area del triangulo: 837
Equivalentemente, existe el procedimiento Readln() que lee el valor de sus
argumentos siempre y cuando no encuentre la secuencia de control < EOL >.
Al programa Cinco se han de introducir los datos de modo distinto que
al Cuatro. Si se utiliza el teclado, hay que teclear el car acter de control
< CR > entre los dos n umeros, puesto que < CR > act ua tambien como
indicador de n de linea.
Program Cinco;
var
resultado, base , altura : Integer;
Begin
{1} Readln(base);
{2} Readln(altura);
{3} resultado := base * altura;
{4} Writeln( Resultado del calculo.);
{5} Writeln(Area del triangulo: :40,resultado:6);
end.
En un archivo, los saltos de carro estan codicados con el car acter ASCII
correspondiente a la secuencia de control < EOL >.
Por ejemplo, un archivo que se imprime o aparece en pantalla del siguiente
modo:
Para vivir no quiero
islas, palacios, torres.
6.4. LAS FUNCIONES WRITELN Y READLN 57
esta almacenado como:
Para vivir no quiero<EOL>islas, palacios, torres.<EOF>
donde < EOF > es la secuencia de control n de chero. El dispositivo
de salida pertinente se encargar a de que aparezcan los dos versos en lneas
distintas.
El procedimiento Readln() utiliza < EOL > como delimitador de su
ambito de lectura y lee los argumentos entre los caracteres que se encuentran
entre dos < EOL >. Por ejemplo, el resultado del programa Cinco, cuando
lee del chero
3
4
es:
Resultado del calculo.
Area del triangulo: 12
mientras que si el chero de entrada es:
3 4
5
la salida sera:
Resultado del calculo.
Area del triangulo: 15
porque la instruccion {1} lee el 3 y omite el 4. La instruccion {2} lee el 5.
58 CAP

ITULO 6. ENTRADA Y SALIDA


Captulo 7
Acciones
7.1 Operaciones basicas.
Una vez conocidos los modos basicos que existen en PASCAL para almacenar
datos en la memoria del ordenador y conocido el modo basico de comunica-
cion con el usuario del programa, pasamos a estudiar que operaciones se
pueden realizar con los datos.
7.1.1 Operadores aritmeticos y expresiones aritmeticas.
Cuando los datos con los que se realizan operaciones son n umeros, lo mas
com un es realizar operaciones aritmeticas : suma, resta, multiplicacion, y
division. En PASCAL estas operaciones se especican con los operadores +
, , * , y / , respectivamente.
Las instrucciones,
a:= 3. + 5.;
b:= a - 2.;
b:= b * a * 6.;
c:= -b / 12.;
son ejemplos de la utilizacion de los operadores. En el caso mas sencillo
de asignaci on con dos operandos solamente, no hay ambig uedad y con este
59
60 CAP

ITULO 7. ACCIONES
formato de instruccion,
variable1 := operando1

operando2;
se asigna a la variable variable1 el resultado de la operaci on aritmetica co-
rrespondiente con las convenciones usuales de la aritmetica. Tanto operando1
como operando2, pueden ser constantes o variables. Cuando se desea operar
con mas de dos datos hay que especicar claramente y sin ambig uedad el
orden en que se quieren realizar las operaciones. Para ello, podemos ayudar-
nos de los parentesis con el mismo n con el que se usan en las expresiones
aritmeticas. Por ejemplo, la siguiente instruccion
b:= ( -37.0 * (a - 2.) ) / (a + 5.);
carece de ambig uedad. No obstante, el PASCAL tiene una prioridad esta-
blecida para el orden de las operaciones:
1. mas y menos monarios.
2. parentesis.
3. multiplicacion y division.
4. suma y resta.
Las siguientes instrucciones son equivalentes:
b:= -27.0 * c + 35. / a + b + c;
b:= ( (-27.0) * c ) + ( 35. / a ) + b + c ;
b:= ( -27.0 * c ) + ( 35. / a ) + b + c ;
y la forma concreta en la que el programador debe escribirla es aquella que
resulte menos confusa. Un error com un entre principiantes es escribir la
instruccion {i} queriendo escribir la {ii} :
{i} b:= a * 27.0 / b + c ;
{ii} b:= a * 27.0 / ( b + c ) ;
{iii} b:= ( a * 27.0 / b ) + c ;
7.1. OPERACIONES B

ASICAS. 61
7.1.2 Funciones aritmeticas.
En PASCAL estan denidas funciones que permiten realizar calculos ma-
tematicos muy frecuentes u operaciones numericas muy utiles para trans-
formar expresiones aritmeticas en sentencias PASCAL . En PASCAL las
funciones son llamadas a procedimientos de calculo que devuelven un valor.
Si aparecen en una expresion aritmetica, las operacion se realiza con el resul-
tado de evaluar la funcion. Si suponemos que se utiliza la funcion para una
asignaci on,
y := F ( x ) ;
los tipos de datos que admiten como argumento, x, los tipos de datos que
proporcionan, y, y las funciones que realizan son:
F ( x ) x y
Abs ( x ) Real o Integer igual que x Valor absoluto
Arctan ( x ) Real o Integer Real Arco tangente
Cos ( x ) Real o Integer Real Coseno
Exp ( x ) Real o Integer Real Exponenciacion ( e
x
)
Frac ( x ) Real o Integer Real La parte decimal de x
Int ( x ) Real o Integer Real La parte entera de x
Ln ( x ) Real o Integer Real Logaritmo neperiano
Pred ( x ) Integer Integer x 1
Random Real N umero aleatorio, y[0, 1]
Random(x) Integer Integer N umero aleatorio, y[0, x]
Round ( x ) Real Integer x redondeado al entero mas cercano
Sin ( x ) Real o Integer Real Seno
Sqr ( x ) Real o Integer Real Exponenciacion ( x
2
)
Sqrt( x ) Real o Integer Real

x
Succ ( x ) Integer Integer x + 1
Trunc ( x ) Real Integer x con la parte decimal eliminada
Las funciones trigonometricas que no estan incluidas, se calculan facilmente
a partir estas. Por ejemplo,
tan1 := Sin(x) / Cos(x);
a := Sin(x);
tan2 := a / Sqrt ( 1.0 - a * a ) ;
62 CAP

ITULO 7. ACCIONES
7.1.3 Aritmetica entera y real.
El PASCAL realiza una comprobaci on escrupulosa del tipo de los datos en
general, y en particular en el procesamiento de las expresiones aritmeticas.
Cuando se programan estas expresiones hay que vericar que se mezclan
coherentemente datos reales y enteros.
PASCAL considera Integer el resultado de una expresion aritmetica
siempre que en la expresion aparezcan solo datos de este tipo y no este
implicada una division. El el programa Uno,
Program Uno;
Var
i,j : Integer;
z : Real;
Begin
{1} j := 8;
(*
{2} i := j / 4; Expresion aritmetica invalida
*)
{3} z := j / 4;
{4} Writeln(z:4:2);
end.
la instruccion {2} es incorrecta, si bien la salida es 2.00 . Por defecto, el
resultado de una expresion aritmetica que no es Integer , es Real . Basta
que haya un solo operando Real o un operador division en una expresion
para que el dato que resulte de la operaci on sea real y que toda la expresion
se eval ue como si todos sus componentes fueran reales.
Cuando se trata de hacer aritmetica de n umeros enteros hay que llevar
mucho cuidado con el lmite de capacidad del tipo de dato que se utilice.
Algunas veces, no es trivial. La salida del programa Dos ,
Program Dos;
Var
i,j : Integer;
z : Real;
Begin
{1} j := 2333;
{2} i := j * 23;
7.1. OPERACIONES B

ASICAS. 63
{3} Writeln(i:9);
(*
{4} i := 2333 * 23; Expresion aritmetica invalida
*)
{5} z := j * 23;
{6} Writeln(z:9:0);
{7} z := 1.0 * j * 23 ;
{8} Writeln(z:9:0);
{9} z := 2333 * 23;
{10} Writeln(z:9:0);
end.
es:
-11877
-11877
53659
53659
La instruccion {2} es aparentemente correcta, pero como el resultado de
la multiplicacion excede la capacidad de un Integer (32767), el resultado
de la operacion es un n umero entero, pero absurdo. Sin embargo, la {4} es
claramente incorrecta y el compilador PASCAL lo detecta al intentar alma-
cenar en el lugar de memoria reservado para i el producto, en vez de generar
el codigo para realizar la multiplicacion durante la ejecucion.
La {5} es solo aparentemente correcta, puesto que es similar a la {2}. Si
bien el resultado de la operacion se quiere almacenar en una variable Real , el
compilador interpreta que la expresion aritmetica se puede realizar con datos
enteros y genera codigo tal que los resultados intermedios se almacenar an en
registros de 2 bytes. El resultado : un desastre, el dato que se almacena
nalmente en la variable real es identico al anterior. Sin embargo, si en la
expresion se incluye cualquier operando Real , el compilador asume que se
trata de una operacion que ha de realizarse con aritmetica real, y utilizara
registros apropiados para esa aritmetica. La instruccion {7} es correcta, y
solo diere de la {5} en la multiplicacion por 1.0, algo matematicamente
irrelevante pero no computacionalmente. Hay que tener siempre presente
que el modo con el que se van a realizar las operaciones de una expresion
64 CAP

ITULO 7. ACCIONES
aritmetica no esta determinado por el lado izquierdo de la asignaci on ( el
tipo de dato que acepta la variable), sino por los operandos.
Cuando aparecen constantes numericas en una expresion aritmetica en la
que se quiere realizar un calculo con n umeros reales, es aconsejable no olvidar
el punto que lo identica como constante real. Si i es una variable Integer
el resultado de estas dos expresiones sera distinto para i > 9.
z := 3600 * i ;
z := 3600. * i ;
Cuando se quieren realizar divisiones respetando la aritmetica de enteros
hay que utilizar el operando Div. El resultado de
j Div i
es j/i cuando j es m ultiplo de i, y la parte de entera de j/i en el caso
contrario.
En el programa Tres ,
Program Tres;
Var
i,j,k : Integer;
Begin
{1} i := 11; j := 6;
{2} k :=10 * ( (i+j) Div j );
{3} Writeln(k:9);
{4} k := 10 * Trunc ( (i+j) / j );
{5} Writeln(k:9);
{6} k := Trunc (10* ( (i+j) / j ) );
{7} Writeln(k:9);
end.
las instrucciones {2} y {4} generan el mismo resultado, pero distinto al de la
{6}. La expresion aritmetica en {6} es el argumento de la funcion Trunc()
y la presencia del operador / indica que se ha de realizar aritmetica de
n umeros reales.
Cuando se quieren utilizar datos Real en expresiones con aritmetica de
n umeros enteros, lo mas apropiado es utilizar la funciones de transformaci on
de tipo, Round() o Trunc() , para homogeneizar el tipo de los operandos.
7.1. OPERACIONES B

ASICAS. 65
Existe otro operador especco de n umeros enteros que es el operador
mod y proporciona el resto de la division entera. El resultado de
j Mod i
es 0 cuando j es m ultiplo de i, y el resto de la division j/i en el caso contrario.
Program Cuatro;
Var
i,j,k,m : Integer;
Begin
{1} i := 11; j := 6;
{2} k :=j mod i;
{3} Writeln(k:9);
{4} m := j * (i mod j) + k;
{5} Writeln(i:9, ,m:9);
end.
La salida del programa Cuatro es:
2
14 14
dado que en la instruccion {4} se recupera para m el valor original de i .
7.1.4 Operadores logicos.
Los operadores logicos que proporciona el PASCAL son de dos tipos:
1. Operadores que actuando sobre datos no-Boolean proporcionando un
dato Boolean.
2. Operadores que actuando sobre datos Boolean proporcionan un dato
Boolean.
El primero de estos tipos es muy util para tomar decisiones como resultado
de la comparaci on de variables. La forma general en la que aparecen estos
66 CAP

ITULO 7. ACCIONES
operadores es:
a

=
<>
>
<
<=
>=

b
donde a y b pueden ser n umeros reales , enteros o caracteres, mientras que
el resultado de la operacion es un dato Boolean (FALSE o TRUE ). La res-
striccion obvia es que a y b han de ser constantes o variables del mismo
tipo.
El resultado de la operacion sera TRUE en los siguientes casos:
Operador Condicion
= a = b
<> a = b
> a > b
< a < b
<= a b
>= a b
En el caso de que de que a y b sean caracteres, las operaciones de comparaci on
se realizan sobre el valor entero del caracter ASCII correspondiente.
Ejemplos de utilizacion de estos operadores son:
Program Cinco;
Var
quizas : Boolean;
letra : Char;
i,j : Integer;
a,tan1,tan2,x : Real;
Begin
{1} i := -11; j := 6; letra := h; x:= 1.3;
{2} quizas := i > j;
{3} Writeln(quizas); (* FALSE *)
{4} quizas := k <= letra ;
{5} Writeln(quizas); (* FALSE *)
{6} tan1 := Sin(x) / Cos(x);
7.1. OPERACIONES B

ASICAS. 67
{7} a := Sin(x);
{8} tan2 := a / Sqrt ( 1.0 - a * a ) ;
{10} quizas := ( tan1 = tan2 );
{11} Writeln(quizas); (* FALSE *)
end.
Merece la pena recordar una vez mas que no se pueden trasladar directa-
mente las expresiones matematicas a las sentencias de un programa. Por
ejemplo, en la instruccion {10} se asigna a quiz as el valor FALSE , si bien
las expresiones utilizadas en las instrucciones {6} y {8} para calcular la
tangente son matematicamente equivalentes. Debido a la utilizaci on de una
representacion nita de los n umeros reales ambos valores seran ligeramente
distintos. La comparaci on para averiguar la similitud de n umeros reales se
suele hacer utilizando la diferencia relativa:
quizas := Abs ( (tan1 - tan2) / tan1 ) <= 0.000001;
Con el segundo tipo de operadores logicos se pueden combinar datos Boolean
para realizar operaciones logicas complejas. Uno de ellos es monario y se
utiliza seg un la forma general:
Not operando
donde tanto operando como el resultado de la operacion son datos del tipo
Boolean. El resultado, es la negaci on del operando:
a Not a
True False
False True
El resto de los operadores se utilizan seg un la forma:
A

And
Or
Xor

B
donde A y B son variables Boolean.
Las tablas de verdad son las habituales:
68 CAP

ITULO 7. ACCIONES
A B A And B
True False False
False True False
False False False
True True True
A B A Or B
True False True
False True True
True True True
False False False
A B A Xor B
True False True
False True True
True True False
False False False
7.1.5 Expresiones logicas.
Denominamos Expresiones logicas a las operaciones que se realizan con da-
tos Boolean. Estas operaciones pueden encadenarse de un modo bastante
complejo. Un ejemplo de utilizacion de estas expresiones es el siguiente:
Supongamos que tenemos que escribir un programa para determinar si
un punto se encuentra en la interseccion de dos rectangulos,
7.1. OPERACIONES B

ASICAS. 69
B
A
y tambien queremos saber si forma parte de la frontera que la delimita. El
programa Seis proporciona la respuesta utilizando expresiones logicas:
Program Seis;
Const
(* Coordenadas cartesianas que definen los rect angulos *)
xa1 = 2; ya1 = 2; { Esquina inferior de A }
xa2 = 7; ya2 = 6; { Esquina superior de A }
xb1 = 5; yb1 = 4; { Esquina inferior de B }
xb2 = 10; yb2 = 8; { Esquina superior de B }
var
dentro1, dentro2, dentrox , dentroy , frontera : Boolean;
puntox,puntoy : Integer;
Begin
{1} Readln(puntox , puntoy); {Coordenadas del punto problema}
(* Sin considerar la frontera *)
{2} dentrox := ( puntox > xb1 ) And (puntox < xa2);
{3} dentroy := ( puntoy > yb1 ) And (puntoy < ya2);
{4} dentro1 := dentrox And dentroy;
{5} Writeln( Si no se considera el borde : ,dentro1);
(* Considerando la frontera *)
{6} dentro2 := ( puntox >= xb1 ) And (puntox <= xa2) And
70 CAP

ITULO 7. ACCIONES
( puntoy >= yb1 ) And (puntoy <= ya2);
{7} Writeln( Si se considera el borde : ,dentro2);
(* Condicion de frontera *)
{8} frontera := dentro2 And ( Not dentro1);
{9} Writeln( Frontera: ,frontera);
end.
Las instrucciones {2} y {3} se podran haber condensado en una sola ins-
truccion similar a la {6}.
Cuando en una expresion se combinan operadores logicos y aritmeticos
hay que utilizar generosamente los parentesis o llevar mucho cuidado con el
orden de prioridad establecido por el PASCAL para la aplicacion de opera-
dores:
Los operadores aritmeticos se aplican siempre antes que los logicos.
Por ejemplo, la expresion
(37 * 4 > 5 * 24) And Not (65 < 2 * 31)
se eval ua a True y los parentesis son estrictamente necesarios. De no existir
el primer juego de parentesis el operador And tendra a su izquierda un dato
Integer y a su derecha un dato Boolean, lo que es incorrecto. De no
existir el segundo juego de parentesis habra tambien una disparidad de tipos
de datos algo mas compleja que se analizar a mas adelante.
Como en el caso de los operadores aritmeticos, en los logicos tambien los
monarios se aplican primero, y en esta expresion el operador Not se aplica
antes que el And.
El uso generoso de los parentesis en las expresiones que mezclan opera-
dores logicos y aritmeticos esta recomendado por otra razon mas:
Los operadores And, Or , y Xor pueden ser aritmeticos o logicos
seg un el tipo de operandos sobre los que act uen.
Esto es as porque como veremos a continuacion tambien estan pensados para
realizar manipulacion de bits.
7.1.6 Manipulaci on de bits.
Existen operadores en PASCAL que permiten modicar directamente los
bits que componen los datos enteros. Estos datos estan almacenados en la
7.1. OPERACIONES B

ASICAS. 71
memoria del ordenador con su valor binario, y los operadores de manipulaci on
de bits permiten al programador modicar directamente los componentes de
la representacion binaria.
En una expresion
A

And
Or
Xor

B
donde A y B son datos enteros ( tipo Integer, Byte, ShortInt, Word
y LongInt ), los operadores And, Or y Xor, act uan como operadores
aritmeticos. El resultado de la operaci on es otro dato entero que se obtiene
realizando la operacion logica correspondiente entre cada uno de los bits de
los datos, considerando el 1 como verdadero y el 0 como falso.
Un dato Byte esta representado en memoria por 8 bits correspondientes
a la representaci on binaria del n umero estando el bit mas signicativo a la
izquierda. Por ejemplo, la representacion interna del dato Byte 77 es:
0 1 0 0 1 1 0 1
y la del dato Byte 62 es :
0 0 1 1 1 1 1 0
La operaci on And entre estos dos datos da como resultado el dato Byte :
0 0 0 0 1 1 0 0
cuyo valor decimal es 12. Si sobre los datos originales se realiza la operacion
Or el resultado es:
0 1 1 1 1 1 1 1
cuyo valor decimal es 127, y si se realiza la operaci on Xor el resultado es:
0 1 1 1 0 0 1 1
72 CAP

ITULO 7. ACCIONES
cuyo valor decimal es 115. Estas tres operaciones son las que se realizan en
el programa Siete :
Program Siete;
Var
a , b , c: Byte;
Begin
a := 77;
b := 62;
c := a And b;
Writeln(c);
c := a Or b;
Writeln(c);
c := a Xor b;
Writeln(c);
End.
Existen otros dos operadores de manipulacion de bits : Shl (Shift left) y
Shr (Shift right). El resultado de
A

Shl
Shr

n
donde A y n son enteros, es otro entero que resulta de desplazar n bits de A
hacia la izquierda (Shl ) o hacia la derecha (Shr ). Los bits que se introducen
en el desplazamiento son nulos. Por ejemplo, si el dato A es,
a
1
a
2
a
3
a
4
a
5
a
6
a
7
a
8
B, el resultado de
B := A Shl 3;
es,
a
4
a
5
a
6
a
7
a
8 0 0 0
y, C, el resultado de
C := B Shr 7;
7.1. OPERACIONES B

ASICAS. 73
es,
0 0 0 0 0 0 0
a
4
Como resultado de la concatenaci on de estas dos operaciones hemos obtenido
un entero cuyo valor es el del quinto bit, empezando por la derecha del entero
original.
El programa Ocho escribe un 1 si el numero que recibe (un entero entre
0 y 255) es impar, y cero de lo contrario:
Program Ocho;
Var
a , b , c: Byte;
Begin
Readln(a);
b := a Shl 7;
c := b Shr 7;
Writeln(c);
End.
En el caso de los datos Integer ( 2 bytes), que permiten almacenar
n umeros enteros con signo, el valor esta almacenado en memoria de un modo
mas complejo. El bit mas a la izquierda de todo almacena el signo: 1 si es
negativo y 0 de lo contrario. El valor del entero esta almacenado en los 15
bits restantes del modo siguiente:
Positivos: El valor binario del entero con el bit menos signicativo a la
derecha.
Negativos: Igual que si fuera positivo pero considerando el valor que
resulta de sumar al entero 32768.
Por ejemplo, -32768 se almacena como:
1000000000000000
y -1 como:
1111111111111111
mientras que 1 se almacena como
0000000000000001
74 CAP

ITULO 7. ACCIONES
y el 32767 como
0111111111111111.
7.2 Sentencias de control.
La mayora de los procedimientos que podemos dise nar para resolver proble-
mas incluyen la eleccion de uno entre los casos posibles en funcion del valor
particular de alguno de los datos. Las sentencias de control en PASCAL son
la condicional simple If y la condicional m ultiple Case.
La sentencia de control simple tiene la siguiente sintaxis:
If datoBoolean
Then
accion1
o bien,
If datoBoolean
Then
accion1
Else
accion2
donde datoBoolean es una variable Boolean o una operacion cuyo resultado
es una dato Boolean, accion1 y accion2 son instrucciones PASCAL que
pueden ser tanto simples como compuestas.
El efecto de esta sentencia de control es el siguiente: si datoBoolean es
True se procede a realizar la instruccion accion1; en el caso de que sea False
y este presente la parte Else, se procede a realizar la instruccion accion2.
En el primero de los casos el esquema de la bifurcacion sera:
7.2. SENTENCIAS DE CONTROL. 75
Boolean

.
.
.

>
>
>
?
accion1
Continuar


Cierto
Falso
y en el segundo caso, cuando esta presente la parte Else de la estructura:
Boolean

>
>
..
?
accion1 accion2
Continuar

En el programa Nueve tenemos un ejemplo de utilizacion de esta construc-


cion. Ambas son equivalentes: en la primera se realiza la comparaci on en la
construccion If, mientras que en la segunda se utiliza una variable Boolean
auxiliar.
Program Nueve;
Var
positivo : Boolean;
n : Integer;
Begin
Readln (n);
If n >= 0
76 CAP

ITULO 7. ACCIONES
Then
Writeln( Se trata de un numero positivo )
Else
Writeln( Se trata de un numero negativo );
positivo := ( n >= 0 ) ;
If positivo
Then
Writeln( Se trata de un numero positivo )
Else
Writeln( Se trata de un numero negativo );
End.
Las acciones que se ejecutan despues de la comprobaci on del dato Boolean
pueden ser instrucciones sencillas o compuestas. En el programa Diez po-
demos ver un ejemplo de utilizaci on con una instruccion compuesta:
Program Diez;
Var
x , y : Real;
Begin { Diez }
{ Programa que calcula la raiz cuadrada de un numero }
Writeln( Calculo de la raiz cuadrada. Escriba el numero);
Readln(x);
If x > 0.0 then
begin
Writeln( Raiz cuadrada: );
y := Sqrt(x);
Write(y)
end
Else
Writeln( Numero negativo.);
End. { Diez }
Con esta estructura If ... Then ... Else tambien se pueden realizar de-
cisiones m ultiples. Un modo muy frecuente de utilizacion es la encadenacion
de estructuras de la forma:
7.2. SENTENCIAS DE CONTROL. 77
If datoBoolean1
Then
accion1
Else
If datoBoolean2
Then
accion2
. . .
En el programa Once se utiliza una concatenaci on de estructuras para rea-
lizar una eleccion m ultiple.
Program Once;
Var
n : Integer;
Begin { Once}
{ Programa que reescribe con letras un numero del 1 al 5 }
Writeln( Teclear un numero del 1 al 5);
Readln(n);
If n = 1 then
Writeln( Uno )
Else If n = 2 Then
Writeln( Dos )
Else If n = 3 Then
Writeln( Tres )
Else If n = 4 Then
Writeln( Cuatro )
Else If n = 5 Then
Writeln( Cinco )
Else
Writeln( Numero fuera de rango);
End. { Once }
Este tipo de bifurcacion m ultiple puede llegar a ser difcil de leer y el
PASCAL proporciona una estructura mas legible para aquellos casos en los
que la bifurcacion m ultiple se realiza mediante comparaci on de datos sencillos
ordinales (por tanto ni Real, ni String). Esta es la estructura Case que
tiene la siguiente sintaxis:
78 CAP

ITULO 7. ACCIONES
Case variable Of
caso1 : accion1
caso2 : accion2
. . .
End;
o bien,
Case identicador Of
caso1 : accion1
caso2 : accion2
. . .
Else
acciond
End;
donde identicador es una variable del tipo Integer, Byte, o Char, las
acciones accion1,... son instrucciones sencillas o compuestas, y los casos
caso1, ... son la especicacion de los valores. Esta especicacion se puede
hacer separando valores con comas o bien mediante el rango, si se trata de
valores consecutivos. Un rango se especica mediante el valor inicial y nal
separados por dos puntos. El programa Doce es equivalente al Once pero
mucho mas legible y eciente.
Program Doce;
Var
n : Integer;
Begin { Doce}
{ Programa que reescribe con letras un numero del 1 al 5 }
Writeln( Teclear un numero del 1 al 5);
Readln(n);
Case n Of
1 : Writeln( Uno );
2 : Writeln( Dos );
3 : Writeln( Tres );
4 : Writeln( Cuatro );
5 : Writeln( Cinco );
Else
7.3. SENTENCIAS DE REPETICI

ON. 79
Writeln( Numero fuera de rango);
End;
End. { Doce }
Un uso mas complejo de la estructura Case se puede ver en el siguiente
ejemplo:
Program Trece;
Var
c : Char;
n : Byte;
Begin { Trece}
{ Programa que identifica un caracter }
Writeln( Teclear el caracter);
Readln(c);
Case c Of
a..z, A..Z : Writeln(Letra);
0..9 : Writeln(Numero);
*,/,+,- : Writeln(Operador aritmetico);
>,<,= : Writeln(Operador logico);
Else
Begin
n := Ord(c);
Writeln(Simbolo ASCII ,n)
end;
End;
End. { Trece }
donde la funcion intrnseca del PASCAL Ord() es una funcion que devuelve
el valor ordinal de cualquier argumento escalar, incluyendo los Char.
7.3 Sentencias de repetici on.
Hay quien opina que la programaci on es una actividad que nunca puede resul-
tar tediosa o repetitiva, ya que todo aquello que ha de hacerse repetidamente
80 CAP

ITULO 7. ACCIONES
puede programarse en una instruccion simple para que sea el ordenador quien
lo haga repetidas veces. De hecho, las sentencias de repeticion son general-
mente las responsables de la utilidad del ordenador. Se trata de instrucciones
que gobiernan la realizaci on de tareas repetitivas mientras no sea cierta la
condicion que se imponga para la nalizaci on.
En PASCAL existen tres estructuras de repeticion que son las construc-
ciones For Do, Repeat Until, y While Do.
La primera de ellas, la construccion For Do, tiene la siguiente sintaxis:
For identicador := principio To nal Do
accion
donde identicador es una variable que puede almacenar un dato ordinal,
principio es el valor que se le asigna a esa variable antes de realizar la accion,
nal es el valor maximo que puede alcanzar la variable antes de nalizar la
accion, y accion es la instruccion, simple o compuesta, del PASCAL que se
repetira incrementando en uno cada vez el valor de identicador. Si se trata
de una sentencia compuesta, tendra que utilizarse la estructura Begin-End
para identicar el principio y el n.
Existe tambien la opcion equivalente
For identicador := principio Downto nal Do
accion
en la que el valor del identicador se decrementa en uno cada vez que se
realiza la accion.
En el programa Catorce tenemos la aplicacion de esta estructura para
el calculo del factorial.
Program Catorce;
Var
z : Real;
n ,i : Integer;
Begin
Writeln(Calculo del factorial (introducir el numero));
Readln(z);
n := Round(z);
If n > 33
7.3. SENTENCIAS DE REPETICI

ON. 81
Then
Writeln( Solo se puede calcular hasta 33!)
Else
Begin
z := 1.;
For i:=1 to n do
z:= z * i;
Writeln(El Factorial de ,n:2, es : );
Writeln(z:40:0)
End;
End.
La limitaci on basica de la estructura For-Do es que la accion que implcitamente
se realiza cada vez es simplemente el aumento o decremento de una varia-
ble ordinal. No obstante, hay que tener presente que variables ordinales no
son solamente los Integer. En el programa Quince vemos como se puede
utilizar la estructura con una variable Char.
Program Quince;
Var
i : Char;
Begin
(* Programa que escribe el alfabeto al reves *)
Writeln();
For i:=Z Downto A do
Write( ,i);
End.
La variable que se utiliza como contador en la estructura For-Do puede
modicarse tambien en la accion que se repite, pero hay que ser extremada-
mente cuidadoso porque de lo contrario podemos generar un bucle innito.
Si en el siguiente programa no se realizara la modicacion a un m ultiplo de
tres, se podra caer en un bucle innito (con probabilidad 0.33333).
Program Dieciseis;
Var
82 CAP

ITULO 7. ACCIONES
i,n : Integer;
Begin
Writeln(Escribo los numeros de dos en dos);
Writeln(Empezando en 1 y acabando en ?);
Readln(n);
n := n - (n Mod 3) ;
For i:=1 to n do
Begin
Writeln(i);
i := i +2
End;
End.
Aceptando que el programa anterior es siempre correcto, es facil deducir
si la comprobaci on sobre el estado del ndice se realiza antes o despues de
incrementar el ndice.
Una estructura muy similar a la For-Do pero mas versatil es la Repeat-
Until. Su sintaxis es:
Repeat
accion1;
accion2;
. . .
Until DatoBoolean
y con ella se especica que se repita el conjunto de acciones situado entre
el Repeat y el Until mientras que no sea True el valor de DatoBoolean .
Las acciones se realizan al menos una vez porque la vericacion sobre el dato
Boolean se hace despues que las acciones. As, en el siguiente programa
el juego no se interrumpe inmediatamente despues de teclear el 0. Por el
contrario la jugada se repite y luego se termina.
Program Diecisiete;
Var
n ,i : Integer;
Begin
Writeln(Adivina el numero que he generado ( del 1 al 9 ));
Writeln( Teclea 0 para terminar );
7.3. SENTENCIAS DE REPETICI

ON. 83
Randomize;
Repeat
i := Random(8);
Writeln(Dime un numero );
Readln(n);
If i+1 <> n
Then
Writeln( No acertaste, era el ,i+1)
Else
Writeln( Si );
Until n = 0 ;
End.
Sin embargo, en la estructura While-Do se realiza la comprobaci on de
la condici on que ha de nalizar la repeticion antes de ejecutarse la accion.
Su sintaxis es:
While DatoBoolean Do
accion
donde DatoBoolean es una expresion cuyo resultado es un dato Boolean,
y accion es una instruccion PASCAL (sencilla o compuesta) que se repetira
mientras DatoBoolean se eval ue a True.
El programa Dieciocho es una modicacion del Diecisiete en el que
con el uso de la estructura While-Do se verica la condicion de n del juego
antes de sortear el n umero.
Program Dieciocho;
Var
n ,i : Integer;
Begin
Writeln(Adivina el numero que he generado ( del 1 al 9 ));
Writeln( Teclea 0 para terminar );
Randomize;
Writeln(Dime un numero );
Readln(n);
While n <>0 do
84 CAP

ITULO 7. ACCIONES
Begin
i := Random(8);
If i+1 <> n
Then
Writeln( No acertaste, era el ,i+1)
Else
Writeln( Si );
Writeln(Dime un numero );
Readln(n);
End; {endwhile}
End.
Cuando se ha de programar un procedimiento repetitivo, la eleccion de una
de las tres estructuras se har a siempre considerando la claridad y facilidad
de programaci on.
En PASCAL tambien existe la sentencia de control no estructurado Goto,
pero no la consideraremos pues en este curso se pretende que el alumno
ejercite la programaci on estructurada. Sin embargo, si que consideramos la
funcion Exit cuya efecto es interrumpir la ejecucion del bloque en la que
se encuentra. Si se trata del programa principal, producira la interrupcion
de la ejecucion del programa. En el programa Diecinueve se modica el
Diecisiete para interrumpir el juego haciendo uso de la funcion Exit.
Program Diecinueve;
Var
n ,i : Integer;
Begin
Writeln(Adivina el numero que he generado ( del 1 al 9 ));
Writeln( Teclea 0 para terminar );
Randomize;
Repeat
i := Random(8);
Writeln(Dime un numero );
Readln(n);
If n = 0 Then Exit;
If i+1 <> n
Then
Writeln( No acertaste, era el ,i+1)
7.4. MANIPULACI

ON DE LOS DATOS STRING. 85


Else
Writeln( Si );
Until n = 0 ;
End.
7.4 Manipulaci on de los datos STRING.
Las sentencias de repeticion son utiles para manipular el contenido de los da-
tos String accediendo a cada uno de los caracteres que componen la cadena.
Como vimos en su da, si s es un dato String ( una ordenaci on consecutiva
de datos del tipo Char) el car acter almacenado en s[0] indica el n umero
de caracteres almacenados en el dato. Ese car acter, como cualquier otro, se
puede convertir a dato entero utilizando la funcion Ord(). Igualmente, se
puede modicar la longitud asignando un nuevo caracter a s[0]. Los carac-
teres almacenados en s tambien se pueden modicar uno a uno y se accede
a ellos mediante s[i] donde i es un entero que corresponde a su n umero de
orden dentro de la cadena. Por ejemplo,
s[2] := b;
hace que el segundo caracter almacenado en s sea el car acter b.
En el programa Veinte tenemos un ejemplo sencillo de manipulacion de
los caracteres de una cadena:
Program Veinte;
Var
s : String[10];
longitud, i : Integer;
Begin
s := ABCDEF;
longitud := Ord(s[0]) ;
Writeln(La longitud original es : ,longitud);
For i:=1 to longitud Do
writeln(Componente ,i:2, : ,s[i]);
s[0]:= Char(3);
s[2] := b;
Writeln(Despues de truncada y modificada: , s);
End.
86 CAP

ITULO 7. ACCIONES
y la salida que produce es:
La longitud original es : 6
Componente 1 : A
Componente 2 : B
Componente 3 : C
Componente 4 : D
Componente 5 : E
Componente 6 : F
Despues de truncada y modificada: AbC
Captulo 8
Modularidad
8.1 Dividir para vencer
Con las estructuras vistas hasta ahora del PASCAL se podran construir
programas que realizaran tareas muy complejas pero con escasa legibilidad.
Un modo muy com un, y generalmente muy efectivo, de resolver un problema
es desmenuzarlo en una serie de problemas mas sencillos y resolver despues
cada uno de ellos. Es la estrategia que ha recibido el nombre dividir y vencer
o dise no Top-Down. Desde el punto de vista de la legibilidad es deseable
que un programa de ordenador pueda estructurarse siguiendo lo mas posible
el esquema conceptual que se ha pensado utilizar para resolver el problema.
Por ejemplo, supongamos que se trata de escribir un programa que calcule
la suma de los n primeros terminos de una sucesion geometrica de razon r y
cuyo primer termino es a. Para ello pensamos utilizar la expresion:
n1

i=0
ar
i
=
a(1 r
n
)
1 r
y el esquema que podemos trazar para el programa es el siguiente:
Suma de la progresion:
(1) Lectura de datos
(2) Calculo de la expresion
(3) Salida de resultados
A su vez, el calculo de la expresion matem atica no es inmediato puesto que
es necesario calcular r
n
donde r es real y n entero. Tambien podemos des-
componer la tarea (2) en:
87
88 CAP

ITULO 8. MODULARIDAD
(2) Calculo de la expresion
(2.1) Obtener r
n
(2.2) Realizar multiplicaciones y divisiones.
A traves de la descomposicion modular que permite el PASCAL con las
construcciones Procedure y Function es posible escribir el programa de
un modo muy similar al pseudo codigo anterior. El cuerpo principal del
programa sera simplemente:
Program SumaProgresion;
Var
n : Integer;
r,a,suma : Real;
(* Declaracion de procedimientos y funciones *)
. . . . . . . . . . . . . . . . . . . .
(* Fin de la parte declarativa *)
Begin { SumaProgesion }
{ Se utiliza la expresion: suma = a (1-r**n) / (1-r) }
LeerDatos(n,a,r);
CalcularExpresion;
SacarResultados(suma);
End. { SumaProgresion}
y en el espacio reservado para declaraciones en el programa se especicara
que tareas se han de realizar en los procedimientos LeerDatos, Calcula-
rExpresion, y SacarResultados, denidos por el programador.
8.2 Procedimientos
La sintaxis con la que se especican estos procedimientos es similar a la de
un programa PASCAL pero se usa la palabra reservada Procedure para
indicar que se trata de un procedimiento parcial:
Procedure nombre ( argumentos ) ;
8.2. PROCEDIMIENTOS 89
Parte declarativa
Begin
Bloque de sentencias del procedimiento
End;
La parte declarativa del procedimiento tiene el mismo n que en un progra-
ma y en ella se denen tipos de datos, variables y constantes como en un
programa y tambien, si as se requiere, procedimientos y funciones que sean
necesarios para la realizacion de este Procedure. En el bloque principal
del procedimiento se escriben las sentencias PASCAL que constituyen el al-
goritmo que ha de realizar, y en el se pueden utilizar datos denidos en su
parte declarativa, en la parte declarativa del programa principal o bien que
aparecen como argumentos del procedimiento. Estos argumentos se utilizan
para comunicar valores de datos al procedimiento desde el bloque donde ha
sido llamado. Cuando se llama al procedimiento, estos argumentos van se-
parados por comas. En la declaracion del procedimiento los argumentos se
especican de un modo muy parecido a como se especica el tipo de datos
en la declaracion de las variables de un programa. Los datos de un mismo
tipo van separados por coma y se utiliza el punto y coma para separar datos
de distinto tipo. A continuacion de los argumentos se especica el tipo de
variable. Por ejemplo, al procedimiento SacarResultados se le llama con el
argumento suma que es un dato Real. Este procedimiento se puede escribir
as:
Procedure SacarResultados(resultado : Real);
Begin { SacarResultados }
Writeln();
Writeln(La suma de la series es: , resultado:10:6);
End; { SacarResultados }
En el argumento se especica el nombre que se va a utilizar en el procedi-
miento y tambien de que tipo de dato se trata. El nombre no ha de coincidir
con el utilizado en el bloque original, puesto que la identicacion de datos la
realiza el compilador por el orden en el que aparecen en el argumento y no
por el nombre.
90 CAP

ITULO 8. MODULARIDAD
8.3 Funciones
Muy parecida a la estructura Procedure es la estructura Function y se
utiliza para aquellos casos en los que se desea que el dato que se calcula en el
modulo independiente pueda aparecer en cualquier instruccion PASCAL en
el mismo lugar en el que aparecera el dato. Este es el caso de las funciones
intrnsecas del PASCAL que ya se han visto. La sintaxis de la estructura
Function es:
Function nombre ( argumentos ) : Tipodato ;
Parte declarativa
Begin
Bloque de sentencias de la funcion
End;
y en el bloque se especica el valor que debe devolver la funcion asign andoselo
al nombre utilizado para nombrar la funcion. Por ejemplo, en el procedi-
miento CalcularExpresion debemos incluir el calculo de la potencia de un
numero real a un exponente entero. Esta operaci on, que puede aparecer en
muchos otros programas, merece la pena que se escriba en un m odulo aparte,
y dado que el resultado es un dato que suele aparecer en expresiones aritme-
ticas, es razonable que se escriba como Function. A la funcion le llamamos
Poten:
{Funcion que eleva un numero real a un potencia entera }
Function Poten ( base : Real;
exponente : Integer ) : Real;
Var
i : Integer;
z : Real;
Begin { Poten }
{1} If exponente <= 0 Then
{2} Poten :=1
{3} Else
{4} If exponente = 1 Then
{5} Poten := base
{6} Else
{7} Begin
{8} z := base;
8.4.

AMBITO DE DEFINICI

ON DE LAS VARIABLES 91
{9} For i := 2 to exponente Do
{10} z := z * base;
{11} Poten := z
{12} End;
End; { Poten }
En el argumento se especican las dos variables con las que nos vamos a
referir al exponente y a la base, el exponente ha de ser un valor entero y
la base puede ser real. A continuacion, se especica que el valor que ha de
devolver la funcion al bloque donde ha sido llamada es Real. Para realizar
el calculo se necesitan otras dos variables y se denen en la parte declarativa.
En las instrucciones {2}, {5} y {11}, aparece el nombre de la funcion en
la parte izquierda de una asignaci on y es en ellas donde se especica el valor
que puede devolver la funcion. La llamada a Poten desde el procedimiento
CalcularExpresi on :
{Calculo de la expresion para la suma de la serie }
Procedure CalcularExpresion ;
Begin { CalcularExpresion }
suma := a * ( 1.0 - Poten(r,n) ) / ( 1.0 - r) ;
End; { CalcularExpresion }
se realiza dentro de una expresion aritmetica.
8.4

Ambito de denici on de las variables
Las variables que se denen en la parte declarativa de un procedimiento
o una funcion existen solamente para ese modulo. Se reservan lugares de
memoria para acomodarlas cuando se requiere el calculo del modulo y se
liberan cuando se termina la ejecucion de los algoritmos especicados en
el modulo. Por tanto, si en alg un otro modulo del programa, o en la parte
principal, se utilizan esas variables, el compilador avisar a de que no se conoce
el tipo de dato de esos identicadores. Por otro lado, se pueden utilizar
los mismos nombres para variables denidas en distintos modulos ya que el
compilador interpretar a correctamente el hecho de que con cada nombre se
reere al lugar de memoria reservado para el dato que se va a manipular en
cada modulo. El unico modo que hay para pasar valores de datos desde un
92 CAP

ITULO 8. MODULARIDAD
modulo a otro, es a traves de los argumentos del Procedure o Function.
Sin embargo, desde el bloque principal se pueden pasar datos a los proce-
dimientos o funciones : cualquier variable o constante denido en la parte
declarativa del bloque principal es accesible a todos los modulos declarados
para el programa (tanto para conocer su valor como para modicarlo). Por
eso, el Procedure CalcularExpresion sin tener ning un argumento puede
acceder al valor de los datos almacenados en las variables n,a y r. Con
esta posibilidad parece logico preguntarse el porque de utilizar argumentos
en los modulos. En particular, el porque de los argumentos en la funcion
Poten. Pues bien, la ventaja de utilizar los argumentos base y exponente
es que, aparte de mejorar la legibilidad, el mismo codigo puede utilizarse
en otros programas independientemente de como se llamen las variables que
intervienen en el calculo.
8.5 Paso de valores por contenido o direcci on
Lo dicho anteriormente sobre las variables denidas en las partes declarativas
de los modulos, tambien es cierto para los argumentos: se reservan para
esos datos nuevos lugares de memoria cada vez que se llama a los modulos,
se copia a ellos los datos almacenados en los argumentos, se utilizan en el
procedimiento y luego se liberan. Por tanto, dentro de un modulo no se puede
alterar el valor de las variables denidas para el bloque que llama al modulo.
Cuando se desee modicar en el modulo el valor de una variable pasada
como argumento hay que especicarlo y as sera accesible al modulo no solo
el contenido de la variable sino tambien su direccion en la memoria. La
especicacion se realiza anteponiendo a estas variables la palabra reservada
Var. Por ejemplo, en el procedimiento Leerdatos
Procedure Leerdatos( Var numero: Integer;
Var primero , razon : Real );
Begin {Leerdatos}
Writeln ( Primer termino de la serie? );
Readln (primero);
Writeln ( numero de terminos? );
Readln (numero);
Writeln ( Razon de la serie? );
Readln (razon);
End; {Leerdatos}
8.5. PASO DE VALORES POR CONTENIDO O DIRECCI

ON 93
se especica que las variables numero, primero, y razon, son argumentos
pasados al modulo por referencia o direccion y no por contenido o valor.
Los datos que almacena el procedimiento en numero, primero, y razon, en
realidad se estan almacenando en los lugares de memoria que el programa
principal reservo para n, a, y r.
El programa completo que realiza la suma de la progresi on es:
Program SumaProgresion;
Var
n : Integer;
r,a,suma : Real;
{ Lectura de datos }
Procedure Leerdatos( Var numero: Integer;
Var primero , razon : Real );
Begin {Leerdatos}
Writeln ( Primer termino de la serie? );
Readln (primero);
Writeln ( numero de terminos? );
Readln (numero);
Writeln ( Razon de la serie? );
Readln (razon);
End; {Leerdatos}
{Funcion que eleva un numero real a un potencia entera }
Function Poten ( base : Real;
exponente : Integer ) : Real;
Var
i : Integer;
z : Real;
Begin { Poten }
If exponente <= 0 Then
Poten :=1
Else
If exponente = 1 Then
Poten := base
Else
Begin
94 CAP

ITULO 8. MODULARIDAD
z := base;
For i := 2 to exponente Do
z := z * base;
Poten := z
End;
End; { Poten }
{Calculo de la expresion para la suma de la serie }
Procedure CalcularExpresion ;
Begin { CalcularExpresion }
suma := a * ( 1.0 - Poten(r,n) ) / ( 1.0 - r) ;
End; { CalcularExpresion }
Procedure SacarResultados(resultado : Real);
Begin { SacarResultados }
Writeln();
Writeln(La suma de la series es: , resultado:10:6);
End; { SacarResultados }
Begin { SumaProgesion }
{ Se utiliza la expresion: suma = a (1-r**n) / (1-r) }
LeerDatos(n,a,r);
CalcularExpresion;
SacarResultados(suma);
End. { SumaProgresion}
El ambito de las variables y la diferencia entre el paso de argumentos por
referencia o contenido se puede apreciar bien con el siguiente programa Uno:
Program Uno;
Var
a , b ,c : Integer;
8.5. PASO DE VALORES POR CONTENIDO O DIRECCI

ON 95
Procedure Escribe ( texto : String;
Var x : Integer;
y : Integer );
Begin { Escribe }
x := 2 * x ;
y := 2 * y ;
Writeln (texto, x:4 , y:4 , c:4 );
End; { Escribe }
Begin
{1} a := 3; b := 5; c:= 7;
{2} Writeln( Antes : , a:4 , b:4 , c:4 );
{3} Escribe(Durante: , a , b );
{4} Escribe(Durante: , a , b );
{5} Writeln(Despues: , a:4 , b:4 , c:4 );
End.
que produce la siguiente salida:
Antes : 3 5 7
Durante: 6 10 7
Durante: 12 10 7
Despues: 12 5 7
La variable c la conoce el procedimiento Escribe porque esta declarada
como variable global para todo el programa. La variable y se pasa por
contenido y por tanto su multiplicacion por 2 en el procedimiento no altera el
valor del dato almacenado en la variable global b. Sin embargo, el argumento
x se pasa por referencia y por tanto cada vez que se llama al procedimiento
se multiplica por 2 el valor almacenado en la variable global a. Cuando
una variable se pasa por referencia el compilador ha de interpretar que cada
vez que se asigne un nuevo valor a esa variable se esta almacenando un
nuevo valor en el contenido de la direccion de memoria que corresponde a
esa variable. Por eso se dice que se esta transmitiendo al procedimiento la
direccion de la variable.
Comprendiendo lo anterior esta claro que las constantes no pueden ser
trasmitidas como argumentos pasados por referencia: las constantes estas en
posiciones en las que no se puede escribir durante la ejecucion del programa.
Por ejemplo, si el procedimiento Escribe se hubiera denido
96 CAP

ITULO 8. MODULARIDAD
Procedure Escribe ( Var texto : String;
Var x : Integer;
y : Integer );
el compilador avisara de que en la instruccion {3} se espera como primer
argumento del procedimiento una variable.
8.6 Denici on diferida
El compilador transforma las ordenes PASCAL a lenguaje maquina empe-
zando por el principio del programa y acabando por el End. Por tanto,
cualquier procedimiento o funcion ha de declarase antes de ser utilizado para
que el compilador cuando llegue al identicador correspondiente sepa inter-
pretar que instrucciones de la Unidad Central de Proceso debe generar. En
general esto implica un orden mnimo a la hora de escribir el programa y lle-
var cuidado de no denir modulos en lneas posteriores a las que los utilizan.
Sin embargo, puede haber ocasiones en las que se requiera que un modulo
llame a otro m odulo y que a su vez llame al primero. En este caso sera im-
posible denir los dos antes de referirlos y por tanto PASCAL proporciona la
palabra reservada FORWARD para seguir al nombre y argumentos de un
procedimiento o funcion cuyo contenido se especicara en lineas posteriores.
En el programa Dos se ilustra el uso de FORWARD :
Program Dos;
Procedure B ( C : Char); FORWARD;
Procedure A ( c : Char);
Begin { A }
If c < Z Then B (c);
Write ( c )
End; { A }
Procedure B ( c : Char);
Begin { B }
A ( Succ (c) )
End; { B }
8.7. M

ODULOS Y SUBM

ODULOS 97
Begin { Dos }
A ( A );
End. { Dos }
El procedimiento B es necesario para denir el contenido de A, y a su vez
A es necesario para denir el algoritmo siniestro que se explicita en B. El
circulo vicioso se rompe adelantando al compilador que B es un Procedure
que toma como argumento un dato Char. Cuando el compilador luego
analiza el procedimiento A reconoce el identicador B y el hecho de que
tome un argumento Char. Entonces, podra generar codigo de la UCP en el
que redireccione el calculo a la direccion de memoria que ya tiene reservada
para el modulo B. Posteriormente, cuando analice la especicacion de los
pasos a realizar en el modulo B generar a el codigo UCP que constituir a
el calculo que se ha de realizar en el procedimiento B. Si todo esto parece
enrevesado mas lo es el modo en que se ha programado el algoritmo que
realiza el programa Dos. Ademas, carece de ning un comentario para que
se pueda calicar como un claro ejemplo de mala programaci on. El alumno,
realizando las instrucciones del programa a mano tardar a alg un minuto en
conocer cual es la salida del programa.
8.7 Modulos y subm odulos
Al igual que para un programa se pueden denir modulos, tambien para un
modulo se pueden escribir otros modulos. Es decir declaraciones de proce-
dimientos cuyo signicado solo conoce el modulo en el que se denen. Por
ejemplo en el programa Tres la funcion Final es local al procedimiento Eco.
Program Tres;
Procedure Eco;
Var
s : String;
Function Final : Boolean;
Var
c : Char;
Begin { Final }
98 CAP

ITULO 8. MODULARIDAD
Writeln( Acabo de hacer el ecooooo ? (s/n) );
Readln(c);
If
(c = s) Or (c = S)
Then
Final := True
Else
Final := False
End; { Final }
Begin { Eco }
Repeat
Readln(s);
Writeln(s);
Until Final;
End; { Eco }
Begin { Tres }
{1}
{2} Eco;
End. { Tres }
de modo que si en la linea etiquetada 1 del cuerpo del programa principal se
a nade la instruccion:
If Final Exit;
para que el usuario pueda acabar tras la primera pregunta, el compilador
avisara de que el identicador Final no esta denido. Esta funcion esta
denida localmente para el procedimiento Eco exactamente como tambien
es local a el la variable s. Esta posibilidad de anidamiento en la denicion
de modulos no se debe utilizar salvo en raras ocasiones pues es origen de
muchas confusiones y es mejor optar por un estilo homogeneo en el que solo
se denen modulos para el programa principal
Un error muy com un en la denicion del contenido de las funciones es el
olvidar asignar un valor al identicador de la funcion. Generalmente no se
trata de una negligencia sintactica sino del olvido de una posibilidad cuando
se hacen asignaciones condicionales. Pero los efectos de este error son menos
alarmantes que los de utilizar el identicador de la funcion en la parte derecha
de una asignaci on en el cuerpo de la funcion. En ese caso, lo mas probable es
8.8. RECURSIVIDAD 99
que se haya escrito un programa que realice un bucle innito. Esta posibilidad
existe puesto que el PASCAL permite la recursividad en la programaci on:
algo que bien utilizado puede aumentar la legibilidad de los programas.
8.8 Recursividad
La denicion de muchos objetos abstractos se realiza mediante recursion. La
recursion aparece generalmente o bien en la denicion de estructuras con
autosemejanza o en la descripcion de procedimientos de calculo matem atico.
Se dice que una denicion es recursiva cuando el objeto denido aparece
en la recursion. Este es un modo de denir objetos muy com un y util. Por
ejemplo, cuando estudiamos el problema de Josefo, se denan los nodos
que componan el crculo como componentes que se identicaban por un
n umero y tenan un enlace con otro nodo. Como veremos posteriormente, la
recursividad es muy util para denir estructuras de datos.
La recursion tambien se utiliza para denir procedimientos de calculo.
En este caso, hay que llevar cuidado en transformar la denicion recursiva
en un algoritmo que se realice en un n umero nito de pasos. Por ejemplo,
consideremos la denici on del factorial de un n umero que se deriva de la
siguiente expresion:
n! = n(n 1)!
Esta igualdad matematica no es un procedimiento de calculo. Para que as
lo sea, hay que a nadir algo mas. En este caso, se trata de algo tan sencillo
como una condicion de principio o n. Si consideramos las dos igualdades:
n! = n(n 1)!
1! = 1
veremos que ya disponemos de un procedimiento para calcular el factorial.
Para calcular, por ejemplo, 4! utilizaramos la secuencia de igualdades:
4! = 4 3! = 4 3 2! = 4 3 2 1! = 4 3 2 1 = 24
La denicion recursiva, y una receta para conocer un valor particular, nos ha
proporcionado un metodo muy claro para calcular el factorial de cualquier
n umero entero n 1. En general una denicion recursiva de un algoritmo
incluye:
100 CAP

ITULO 8. MODULARIDAD
La relaci on con el caso mas peque no.
La condicion de nalizacion.
El PASCAL , como cualquier lenguaje moderno de programaci on permi-
te la programaci on recursiva: en la denicion de un modulo, Procedure
o Function, puede aparecer una llamada a el mismo. El programa para
calcular el factorial podra ser:
Program Factoriales;
Var
m :Integer;
Function Fac ( n : Integer ) : Integer;
{ Utiliza la definicion n! = n (n-1)! }
Begin
{1} If n <= 1 Then
{2} Fac := 1
{3} Else
{4} Fac := n * Fac ( n - 1 )
End;
Begin
Writeln(Calculo de factorial. Introducir el numero:);
Read( m );
If m > 7 Then
Writeln(El numero es demasiado grande.)
Else
Writeln (El factorial de, m:2 , es , Fac (m) )
End.
Como se utilizan datos Integer este programa solo sera capaz de calcular
hasta el factorial de n umeros peque nos pues crece muy r apidamente y a partir
de 7! se desborda la capacidad de almacenamiento de ese dato. Por lo demas,
se trata de un programa de facil lectura. En la instruccion {2} consideramos
el valor de terminaci on de las llamadas recursivas. Sin ella, el programa no
acabara nunca. En la instruccion {4} estamos diciendo que en esa llamada
se asigne a la funcion Fac el valor que se obtiene multiplicando el valor actual
8.8. RECURSIVIDAD 101
de n por el resultado que se obtenga al llamar a la funcion Fac con el valor
decrementado en 1.
Generalmente, la recursividad mejora la facilidad de escritura de algo-
ritmos y su legibilidad. Sin embargo, los programas que resultan suelen ser
menos ecientes que aquellos que hacen la misma tarea sin usar la recursi-
vidad (en el programa Catorce del tema anterior vimos el caso no recursi-
vo). Muy frecuentemente, se utiliza el algoritmo recursivo como una primera
aproximaci on a la resolucion del problema. Posteriormente, un an alisis mas
profundo de este, puede llevar a otro algoritmo no recursivo y que se ejecuta
con menos gasto de recursos. La primera version recursiva, conceptualmente
mas sencilla, siempre sirve para comparar los resultados del algoritmo mas
elaborado.
Como se menciono anteriormente, la posibilidad de recursividad que ofre-
ce el PASCAL puede dar lugar a errores de programaci on con resultados mo-
lestos. Si por error en una funcion aparece el nombre de una funcion en el
lado derecho de una asignaci on, el compilador no avisar a de tal error, pues
sintacticamente corresponde a una llamada recursiva, y es muy probable que
se obtenga un bucle innito.
102 CAP

ITULO 8. MODULARIDAD
Captulo 9
Datos con estructura
Un programa de ordenador esta constituido por algoritmos que manejan la
informaci on almacenada en la memoria del ordenador. El modo en el que
esta informaci on puede ser referenciada por el programador es esencial para
la ecacia y legibilidad de los algoritmos. Hasta ahora hemos visto tipos de
datos muy elementales. En este tema se consideran opciones mas avanzadas
al estudiar los tipos de datos denidos por el programador y datos que poseen
estructura interna.
9.1 Tipos de datos denidos por el progra-
mador
Ya se han estudiado tipos de datos elementales como los Integer, Real,
Char, etc. En este tema se estudiar an otros tipos de datos denidos en
PASCAL . Pero tambien puede el programador denir tipos de datos a la
medida de sus necesidades. Con la palabra reservada Type se puede informar
al compilador sobre la interpretaci on de variables que van almacenar el nuevo
tipo de dato. Esta denicion de nuevos tipos de datos se incluye en la parte
declarativa del programa, antes de que se referencie ese nuevo tipo de dato,
y con la siguiente sintaxis:
Type
Indenticador1 = Untipo1;
Indenticador2 = Untipo2;
. . .
103
104 CAP

ITULO 9. DATOS CON ESTRUCTURA


donde Indenticador1,Indenticador2, etc., son los nombres que se han asig-
nado a los nuevos tipos de datos , y Untipo1,Untipo2, etc., es la especicacion
de que tipo de dato se trata.
La utilizacion mas trivial que se puede pensar para esta posibilidad es la
de renombrar la denominacion de los tipos de datos estandard. Por ejemplo,
Program Uno;
Type
Entero = Integer;
Var
i,n : Entero;
. . . . . .
con estas declaraciones se informa al compilador de que cuando se denen las
variables i,n como Enteros , nos referimos a datos Integer. Obviamente,
la posibilidad de denicion de tipos de datos existe para realizar cosas mas
utiles que simplemente renombrar. Por ejemplo, se puede utilizar para denir
variables enteras con un rango acotado. En el programa Uno se utiliza esta
posibilidad:
Program Uno;
Type
Nota = 0..10;
Var
i : Nota;
Begin
Writeln(Teclear la nota (0 a 10):);
Readln(i);
Case i Of
0..4 : Writeln(Suspenso);
5..10 : Writeln(Aprobado)
End;
End.
Se dene el tipo de dato Nota que es un entero en el rango entre 0
y 10. La primera de las instrucciones del programa es una orden para el
compilador de TURBO PASCAL , que le indica que genere codigo de UCP
en el que se realice comprobaci on de rangos de variables durante la ejecucion
9.2. ENUMERACIONES 105
del programa. Con esta opcion, si se teclea un dato fuera del rango denido
para Nota aparecer? un mensaje de error Run time. Sin esa opcion del
compilador, no aparecera ning un mensaje de error.
9.2 Enumeraciones
Los tipos de datos Integer, Char y Byte son ejemplos de tipos de datos
en los que se puede almacenar un n umero limitado de datos. En el tipo
Byte, por ejemplo, n umeros entre el 0 y el 255. Si el programador necesita
utilizar un conjunto limitado de datos puede referirse a ellos estableciendo
explcitamente una relacion entre cada dato y uno de los valores que pue-
de tomar un tipo de dato limitado. Por ejemplo, si queremos referirnos a
los meses de a no en un programa se puede establecer una relaci on entre un
n umero y el mes, empezando con el 1 para Enero y siguiendo hasta 12 con
el orden del calendario. Dado el uso cotidiano de esta relacion resultara
muy facil escribir y leer programas en los que se utilizara una variable mes
del tipo Byte. Siempre que mes tomara el valor 2 el programador inme-
diatamente interpretara ese valor como el mes de Febrero. Sin embargo, en
otras muchas ocasiones no existir a tal correlaci on cotidiana entre ordinales
y objetos. Por ejemplo, si en un programa se quiere operar con datos del
tipo color, considerando las posibilidades Rojo , Amarillo , Naranja, Verde
, y Azul, no es facil elegir una ordenacion entre ellos que permita establecer
una relaci on facilmente comprensible entre un n umero, por ejemplo del 0 al
4, y cada color. Para estos casos el PASCAL permite establecer esa relacion
en la denicion de un tipo y el programador puede olvidarse de ella durante
el programa. Un tipo de dato enumerado se especica con el conjunto de
posibilidades entre parentesis y separadas por comas. En el programa Dos
tenemos un ejemplo de su utilizacion:
Program Dos;
Type
Color = (Rojo , Amarillo , Naranja, Verde , Azul);
Var
i : Color;
Begin
i := Amarillo;
Case Succ(i) Of
Amarillo : Writeln(Se trata de Amarillo);
106 CAP

ITULO 9. DATOS CON ESTRUCTURA


Naranja : Writeln(Se trata de Naranja);
End;
Writeln(Ord(i));
End.
El tipo de dato Color se dene como la enumeraci on de esos cinco colores.
La variable i se dene como un Color y por tanto puede tomar el valor
Amarillo. El compilador establece una relacion unvoca entre cada uno de
los posibles valores y un n umero. Por tanto sobre este tipo de dato se puede
operar con las funciones que admiten argumentos ordinales, entre otras Succ
y Pred. Este programa escribira primero : Se trata de Naranja porque el
sucesor del valor Amarillo es Naranja. De hecho, la relacion que establece
el compilador entre valores y n umeros es sencillamente el n umero de orden,
empezando por 0, en el que aparece cada valor en la enumeraci on que se
utiliza para declarar el tipo. Por tanto, el programa acabar a su ejecucion
escribiendo el n umero 1.
Este tipo de datos enumerado se suele utilizar para facilitar la tarea de
programar (escritura y lectura), y no se pueden leer o escribir. Por ejemplo,
la instruccion Readln(i); no sera valida en el programa Dos. Sin embargo,
se puede establecer la relaci on entre un ordinal y el valor de un tipo de dato
enumerado que aparece en ese lugar en la denicion. Por ejemplo, la primera
instruccion del programa Dos se podra reemplazar por
i:= Color(1);
Otra utilidad de los tipos de datos enumerados es la formaci on de conjun-
tos con la posibilidad que ofrece el PASCAL de operaciones entre conjuntos.
9.3 Conjuntos
Un conjunto de datos del tipo Cualquiera se dene con la siguiente sintaxis:
Type identicador Set Of Cualquiera
donde identicador es el nombre elegido para el nuevo tipo de dato, y cual-
quiera es el tipo de dato de los elementos que forman el conjunto. Los
elementos pueden ser cualquier tipo de dato ordenado, y entre ellos los enu-
merados.
9.3. CONJUNTOS 107
La especicacion de los miembros de un determinado conjunto se realiza
escribiendo los elementos, uno a uno, o mediante rangos, entre parentesis
cuadrados. El el programa Tres se ilustra el uso de los conjuntos:
Program Tres;
Type
Meses = ( enero , febrero , marzo , abril , mayo , junio,
julio , agosto , septiembre , octubre,
noviembre, diciembre );
Estacion = Set Of Meses;
Var
n : Integer;
mes : Meses;
otogno,invierno,primavera,verano,cambio: Estacion;
Begin
invierno := [diciembre ,enero .. marzo ];
primavera := [marzo .. junio];
verano := [junio .. septiembre];
otogno := [septiembre .. diciembre];
{ Los meses de cambio de estacion son la suma de las
interseciones de las estaciones }
cambio := invierno * primavera + primavera * verano +
verano * otogno + otogno * invierno;
Writeln(teclear en numero del mes (de 1 a 12):);
Readln(n);
mes := Meses( n - 1);
If mes In cambio Then Write( Cambia la estacion : );
If mes In verano Then Write( verano );
If mes In otogno Then Write( otogno );
If mes In invierno Then Write( invierno );
If mes In primavera Then Write( primavera );
Writeln();
End.
El operador In se utiliza para determinar si un elemento se encuentra dentro
de un conjunto, con la siguiente sintaxis:
108 CAP

ITULO 9. DATOS CON ESTRUCTURA


NomElemento In NomConjunto
donde NomElemento es el nombre del elemento sobre el que se inquiere y
NomConjunto el conjunto. El resultado de esta operacion es un dato Boo-
lean, y se eval ua a True solo si el elemento pertenece al conjunto.
En el programa Tres tambien se ilustra la asignaci on de valores a los
conjuntos, si bien falta a nadir que tambien se puede asignar el conjunto
vaco ([] ).
Los operadores aritmeticos y logicos cuando act uan entre conjuntos tienen
un signicado nuevo. Si A, B y C son conjuntos de elementos del mismo tipo,
las operaciones permitidas son :
C := A + B {C : conjunto union de A y B}
C := A * B {C : conjunto interseccion de A y B}
C := A - B {C : conjunto diferencia de A y B}
Tambien se pueden comparar los conjuntos con los operadores logicos dando
lugar a un dato Boolean. Si A y B son dos conjuntos de elementos del
mismo tipo y verdad un dato Boolean, las comparaciones siguientes son
posibles:
verdad := A = B {verdad es True si A y B son iguales}
verdad := A <> B {verdad es True si A y B son distintos}
verdad := A <= B {verdad es True si A es subconjunto de B}
verdad := A => B {verdad es True si B es subconjunto de A}
teniendo en cuenta que el conjunto vaco es subconjunto de todo conjunto.
Tambien hay que tener en cuenta que el n umero de elementos que pueden
formar un conjunto en PASCAL esta limitado a un maximo de 256.
9.4 Arrays
Cuando se tiene que seguir la pista a un grupo o de datos es muy util re-
ferirse a todos ellos con un mismo nombre y distinguir entre los elementos
mediante el lugar que ocupan en el grupo. En realidad de trata de ampliar la
conveniencia de los conjuntos estudiados anteriormente a grupos de datos de
cualquier tipo. En el Array los elementos del grupo se ordenan asignandose
a cada elemento un n umero de orden o direccion. El tipo de dato Array (
tabla ) es uno de los datos con estructura mas importantes de un lenguaje.
Esto es as, porque corresponde a una ordenaci on de datos similar a la que se
9.4. ARRAYS 109
realiza en la memoria central del ordenador. Se puede pensar que un Array
es un conjunto de celdillas contiguas, en cada una de ellas se puede almace-
nar un dato simple, y cada dato simple esta identicado por la posicion que
ocupa en esa tabla. La ventaja de esta estructura es que se tarda el mismo
tiempo en acceder a cualquier elemento, ya que se accede a el exclusivamente
por su direccion. La desventaja, es que se trata de un estructura estatica en
el sentido de que la longitud maxima de la tabla se ha de especicar a priori.
Para denir el tipo de dato Array se utiliza la siguiente sintaxis:
Array [ rango ] Of tipo
donde tipo es el tipo de datos que se almacena en cada una de las posiciones
de la tabla y rango la especicacion del rango de variaci on del ndice (entero)
que identica las posiciones de los elementos de la tabla. Este rango se
concreta especicando el primer y ultimo ndice separados por dos puntos
consecutivos. Solo se permite un rango consecutivo.
La especicacion de Array puede aparecer tanto en una denicion de
tipo de dato, por ejemplo,
Type
vector = Array [1..30] Of Real;
o directamente en la declaracion de una variable, por ejemplo,
Var
texto : Array [0..3000] Of Char;
El ndice que sirve para especicar la posicion de los elementos no tiene
porque empezar en 0 o 1. Si para el programa tiene sentido utilizar un rango
como [127..345], es perfectamente valido. Para acceder a un elemento de
un Array se utiliza el identicador seguido de su ndice entre parentesis
cuadrados.
En el programa Primos tenemos un ejemplo de utilizacion de esta estruc-
tura de datos. Se trata de la determinacion de n umeros primos utilizando el
famoso algoritmo de la criba de Erat ostenes.
Program Primos;
Const
MAX = 1000;
{ Calculo de los numeros primos entre 1 y MAX
utilizando el algoritmo de la Criba de Eratostenes }
110 CAP

ITULO 9. DATOS CON ESTRUCTURA


Var
esPrimo : Array [1..MAX] of Boolean;
i,j : Integer;
Begin { primos }
{Se inicializa la tabla}
esPrimo[1] := False;
For i := 2 to MAX Do esPrimo[i] := True;
{En la criba de Eratostenes se parte de todos los numeros
y se van eliminando todos los multiplos de los primos
elegidos. Seran primos elegidos aquellos que , en orden
ascendente, no hayan sido marcados como multiplos }
For i := 2 To MAX Div 2 Do
For j := 2 To MAX Div i Do
esPrimo[i*j] := False;
{Se cuenta el numero de primos encontrados }
j:= 0; For i := 1 To MAX Do If esPrimo[i] Then j := j + 1;
Writeln(Entre 1 y ,MAX:5, se han encontrado , j:3, primos);
For i := 1 To MAX Do If esPrimo[i] Then Write(i:4);
End. { primos }
Se dene el Array esPrimo para almacenar datos Boolean que permiten
seguir la pista de los n umeros que son m ultiplos de otros. En este programa
se hace un uso apropiado de la ventaja ofrecida por la estructura de dato
Array. Se utiliza un tiempo constante para acceder a cualquier elemento de
la tabla, independientemente de que se trate del primero o el ultimo. Ademas
se puede incluir en el programa una relaci on ventajosa entre la posicion de
un elemento en la tabla y su signicado.
La estructura Array se usa muy a menudo en el calculo cientco, pues
se trata de la realizacion de un vector, si cada elemento de la tabla se inter-
preta como un componente del vector. Igualmente, se pueden denir tablas
de tablas (Array bidimensional) para manipular matrices, y Array multi-
dimensionales para los tensores.
La especicacion del rango, cuando se declaran, en los Array multidi-
mensionales se puede realizar separando con comas los rangos de cada una
de las dimensiones. Igualmente, el acceso al contenido de una posicion de
9.4. ARRAYS 111
estas tablas m ultiples se puede realizar separando con comas los ndices de
cada una de las dimensiones.
El siguiente procedimiento MultMatriz se puede utilizar para multipli-
car matrices.
Program Cuatro;
Const
MAXDIM = 20;
Type
Numeros = Real;
Matriz = Array[1..MAXDIM,1..MAXDIM] Of Numeros;
Var
n : Integer;
A,B,C : Matriz;
Procedure Leematriz ( Var X : Matriz); FORWARD;
Procedure Escribematriz ( X : Matriz); FORWARD;
Procedure MultMatriz ( dim : Integer;
Var
A1 , A2 , M : Matriz );
Var
i,j,k : Integer;
x : Numeros;
Begin { MultMatriz }
For i := 1 To dim Do
For j := 1 To dim Do
Begin
x:= 0.0;
For k := 1 To dim Do
x := x + A1 [i,k] * A2 [k,j];
M[i,j] := x;
End; {End del doble For}
End; { MultMatriz }
{ Aqui se encontrarian las definiciones de los }
{ dos procedimientos que se han omitido }
Begin
Writeln(Dimension de las matrices: );
Readln(n);
Leematriz(A); Leematriz(B);
112 CAP

ITULO 9. DATOS CON ESTRUCTURA


MultMatriz(n,A,B,C);
Writeln(La Matriz producto es:);
Escribematriz(C);
End.
Pero la denicion de los Array miltidimensionales tambien se puede hacer
como una tabla de tablas. Por ejemplo, el tipo de dato Matriz se podra
haber denido del siguiente modo:
Matriz = Array[1..MAXDIM] Of Array [1..MAXDIM] Of Numeros;
e igualmente los componentes de este tipo de datos se pueden referir como:
x := x + A1 [i][k] * A2 [k][j];
Ambas deniciones y utilizaciones son equivalentes. Las limitaciones de las
estructuras Array denidas de este modo estan en la capacidad de almacena-
miento. Una estructura Array no puede ocupar toda la memoria disponible
en el ordenador por muchos motivos que se estudiaran en el tema de gestion
de memoria. Basta con uno de ellos: en TURBO PASCAL no se puede crear
un Array que ocupe mas de un segmento de memoria (2
16
= 65, 536 bytes ).
La estructura de datos String es simplemente un caso especial de tabla de
datos tipo Char en el que se reserva la posicion dendice cero para almacenar
el car acter correspondiente al n umero que indica los elementos almacenados.
Ya vimos en su da que el tipo de datos String tiene su capacidad limitada a
255 caracteres. El programador puede muy facilmente denir un tipo de dato
similar al String con capacidad superior. En este caso, tendra que denir
sus propias funciones para manipularlos. La siguiente funcion Concatena
podra ser la funcion que uniera dos de estas cadenas de caracteres.
Program Cinco;
Const
MAXDIM = 300;
{ Los caracteres se guardan en enteros como su ordinal }
Type
Cadena = Array[0..MAXDIM] Of Integer;
Var
A,B : Cadena;
Procedure LeeCadena (Var x : Cadena);
9.4. ARRAYS 113
Var
i : Integer;
c : Char;
Begin { LeeCadena }
i:= 1;
Repeat
Read(c);
x[i] := Ord(c);
i := i+1;
Until ( EOLN );
x[0] := i - 1;
{ Lee los caracteres ASCII 13 (CR) y 10 (LF)
que delimitan el fin de linea }
Read(c);Read(c);
End; { LeeCadena }
Procedure EscribeCadena ( x : Cadena);
Var
i: Integer;
Begin { EscribeCadena }
For i := 1 to x[0] Do Write(Chr( x[i] ));
End; { EscribeCadena }
{ Procedimiento para unir a la cadena A1 la cadena A2 }
Procedure Concatena ( Var
A1 , A2 : Cadena );
Var
dim1 , i : Integer;
Begin
dim1 := A1[0];
For i := 1 To A2[0] Do
A1[ dim1 + i ] := A2[i];
A1[0] := dim1 + A2[0];
End;
Begin
Writeln();
114 CAP

ITULO 9. DATOS CON ESTRUCTURA


LeeCadena(A);
LeeCadena(B);
Concatena(A,B);
Writeln();
EscribeCadena(A);
End.
Se aprecia en la funcion Concatena que el hecho de poder acceder a la
longitud de la cadena permite escribir algoritmos muy ecientes de cadenas
de caracteres. Sin embargo, esta estructura denida para las cadenas de
caracteres es ineciente en cuanto almacenamiento. Se estan almacenando
los caracteres ASCII en 2 bytes mientras que sera suciente uno solo.
9.5 Registros
La situacion encontrada en el problema planteado anteriormente de manipu-
lacion de cadenas es muy com un. Lo mas frecuente es encontrarse en una
situacion en la que se quiere representar en un tipo de dato una informaci on
que posee estructura interna y es heterogenea, es decir, los campos en los que
se subdivide el dato no son todos del mismo tipo. Para ello el PASCAL, como
otros lenguajes de programaci on actuales, suministra los datos tipo registro
(en ingles records).
Un registro es un tipo de dato denido por el programador en el que
puede especicar su estructura interna.
El programador da nombre al nuevo tipo de dato y a cada uno de los
campos que lo componen, y especica el tipo de dato que puede ocupar cada
uno de los campos. La sintaxis para estas especicaciones es:
Type
nombre =
Record
NombreCampo1 : TipoDato1 ;
NombreCampo2 : TipoDato2 ;
. . .
End;
donde nombre es el identicador elegido para el registro, y NombreCam-
po1 , NombreCampo2 , ... son los identicadores elegidos para los distintos
9.5. REGISTROS 115
campos. TipoDato1 , TipoDato2, ... son la especicacion del tipo de dato
que se va a almacenar en cada uno de los campos. Esta especicacion puede
corresponder a un tipo de dato estandard del PASCAL , la enumeracion o el
rango de los posibles valores, u otro tipo de dato declarado con anterioridad.
Por ejemplo, hay casos en los que puede ser conveniente denir un tipo de
variable para almacenar la informaci on de una fecha. Una posible denicion
es la siguiente:
Program Seis;
Type
Fecha =
Record
mes : 0 .. 12; { 0 seria para indicar que no se conoce la fecha}
dia : 1 .. 31;
agno : Integer ;
End;
Var
alta , baja : Fecha;
El modo en el que se especica reriendose a una variable del tipo Record
un determinado campo, es a nadiendo al nombre de la variable el nombre
dado al campo, y unidos por un punto. El ejemplo anterior podra continuar
del siguiente modo
Begin
alta.dia := 27 ;
alta.mes := 2 ;
alta.agno := 1992;
baja.mes := alta.mes + 2;
....
Tambien el PASCAL permite la comodidad de la estructura With para ac-
ceder a los valores de los campos de los registros. La sintaxis de la estructura
With es la siguiente :
With nombre Do accion
donde nombre es la especicacion de la variable ( o las variables separadas por
comas ) del tipo Record a la que se reere la instruccion PASCAL accion
116 CAP

ITULO 9. DATOS CON ESTRUCTURA


que se encuentran a continuacion del Do. Si se trata de una instruccion
compuesta se encontrar a, como siempre, horquillada entre un Begin y un
End. En la instruccion del With podemos especicar los distintos datos
del registro con solo el nombre de los campos. Por ejemplo, las instrucciones
anteriores, se podran haber escrito del siguiente modo:
Begin
With alta Do
Begin
dia := 27 ;
mes := 2 ;
agno := 1992;
baja.mes := mes + 2;
End;
....
La eleccion del uso de la estructura With se suele hacer en cada caso par-
ticular seg un la legibilidad que a nada al programa.
Ya hemos dicho que los campos de los registros pueden contener datos que
son del tipo registro. En ese caso, como siempre, habra que llevar cuidado en
denir los tipos de datos en el orden adecuado para que nunca aparezca en
una declaraci on un tipo de dato que no ha sido declarado en pasajes anteriores
del programa. Si ampliamos el ejemplo anterior hacia la construccion de una
base de datos con los alumnos y sus notas, un programa de captacion de
datos podra empezar as:
Program Siete;
Type
Fecha =
Record
mes : 0 .. 12; { 0 seria para indicar que no se conoce la fecha}
dia : 1 .. 31;
agno : Integer ;
End;
Alumno =
Record
nombre : String;
apellidos : String;
9.5. REGISTROS 117
nacimiento : Fecha;
nota : Real;
End;
Var
uno,otro : Alumno ;
Begin
Writeln(Nombre : ) ; Readln(uno.nombre);
Writeln(Apellidos : ); Readln(uno.apellidos);
Writeln(Agnno de nacimiento : ); Readln(uno.nacimiento.agno);
Writeln(Mes de nacimiento: ); Readln(uno.nacimiento.mes);
Writeln(Dia de nacimiento: ); Readln(uno.nacimiento.dia);
Writeln(Nota del examen: ); Readln(uno.nota);
. . . . . . . . . . . . . .
y vemos que la referencia a los campos de registros que son a su vez campos
de un registro se realiza concatenando con puntos los identicadores de los
campos.
Para crear una base de datos que contuviera informaci on de los alumnos
de una clase lo logico sera ordenar los alumnos en una lista. Para ello, se
puede crear una estructura Array cuyos elementos sean los registros deni-
dos para almacenar la informacion de los alumnos. Se podra por ejemplo
a nadir en la parte declarativa del programa Siete el siguiente tipo de dato:
{ Type }
Lista =
Array[1..100] of alumno;
y tambien una variable de este tipo:
{ Var }
primero : Lista;
El acceso a los elementos del Array es el habitual. Por ejemplo, el programa
Siete podra continuar del siguiente modo:
primero[1] := uno;
If (Primero[1].nacimiento.mes = 12 ) Then ......
118 CAP

ITULO 9. DATOS CON ESTRUCTURA


En la primera de estas instrucciones se asigna al elemento primero del Array
primero el dato almacenado en uno (con todos sus campos de una sola
vez). En la segunda, se comprueba el valor que tiene el dato almacenado
en el campo mes del campo nacimiento de la variable del tipo Alumno
almacenado en la posicion primera del Array primero.
Tambien existe, obviamente, la posibilidad inversa: la de denir registros
en los que sus campos sean datos con la estructura Array. Podemos retomar
ahora el problema estudiado anteriormente de cadenas de caracteres y uti-
lizando registros disponer de una estructura de datos con aprovechamiento
eciente de la memoria. El tipo de dato Cadena se dene ahora como un
registro con un campo que es el n umero de caracteres almacenados y el otro
campo el Array de caracteres. As, para la longitud utilizamos un Integer
y para cada caracter un solo byte.
Program Ocho;
Const
MAXDIM = 300;
Type
Ristra = Array [1..MAXDIM] of Char;
Cadena =
Record
longitud : Integer;
contenido : Ristra;
End;
Var
A,B : Cadena;
Procedure LeeCadena (Var x : Cadena);
Var
i : Integer;
c : Char;
Begin { LeeCadena }
i:= 1;
With x Do
Begin
Repeat
Read(c);
contenido[i] := c;
i := i+1;
9.5. REGISTROS 119
Until ( EOLN );
longitud := i - 1;
End;
{ Lee los caracteres ASCII 13 (CR) y 10 (LF)
que delimitan el fin de linea }
Read(c);Read(c);
End; { LeeCadena }
Procedure EscribeCadena ( x : Cadena);
Var
i: Integer;
Begin { EscribeCadena }
For i := 1 to x.longitud Do Write(x.contenido[i] );
End; { EscribeCadena }
{ Procedimiento para unir a la cadena A1 la cadena A2 }
Procedure Concatena ( Var
A1 , A2 : Cadena );
Var
dim1 , i : Integer;
Begin
dim1 := A1.longitud;
For i := 1 To A2.longitud Do
A1.contenido[ dim1 + i ] := A2.contenido[i];
A1.longitud := dim1 + A2.longitud;
End;
Begin
Writeln();
LeeCadena(A);
LeeCadena(B);
Concatena(A,B);
Writeln();
EscribeCadena(A);
End.
Despues de estudiar todos estos tipos de datos denidos por el usuario
120 CAP

ITULO 9. DATOS CON ESTRUCTURA


debe estar mucho mas claro el sentido de los conceptos tipo de dato y va-
riable. Una variable, es un identicador que utiliza el programador para
referirse a un dato y poder realizar operaciones con el. El tipo de dato ha de
especicarse para que el compilador pueda generar codigo UCP en el que se
utilice una cantidad de memoria suciente para ese dato y estructurada del
modo adecuado. Cuando el programador se enfrenta a la resolucion de un
problema puede pensar en variables para cualquier concepto abstracto que
piense que sea util para resolver el problema de un modo claro y comunica-
ble, lo que muchas veces quiere decir de un modo lo mas proximo posible al
lenguaje natural. La restriccion obvia es poder explicitar sin ambig uedades
la gesti on de la memoria del ordenador que ha de realizar el compilador para
almacenar y manipular ese dato. Mediante la estructura Record y Array
el PASCAL ofrece la posibilidad de denir tipos de datos muy pr oximos a
los utilizados en el lenguaje natural y que son una organizaci on precisa de
tipos de datos mas sencillos. En ultima instancia, los atomos que van a for-
mar esas estructuras mas complejas son los tipos de datos fundamentales del
PASCAL : Byte , Integer , .... Al nal, para una variable, el compilador
reservar a lugar en memoria para almacenar un n umero determinado de bits
de informaci on (una sucesion de ceros o unos). El tipo de dato denido para
esa variable va a determinar el modo en el que esos bits van a intervenir en
las operaciones y tambien el modo con en el que el programador se podra
referir a todos esos bits de golpe o a subconjuntos de ellos.
9.6 Uniones
Comprendido lo anterior no debe resultar difcil entender dos posibilidades
avanzadas que permite el PASCAL en la manipulaci on de registros, y que
son los registros con variante ( o uniones con discriminacion) y las uniones
libres. En PASCAL es posible dar una denicion din amica de la composicion
de un registro. Es decir, que los campos que lo componen varen seg un el
valor de un par ametro. Para ello se utiliza la siguiente modicacion de la
estructura Case dentro de la denicion del registro:
Case
nombre : TipodeDato Of
caso1 : ( Especicacion1 );
caso2 : ( Especicacion2 );
. . .
9.6. UNIONES 121
donde nombre es el identicador elegido para la variable cuyo valor deter-
mina la composicion del registro, TipodeDato el tipo de dato de la variable
nombre, caso1,caso2, ... los valores o rango de valores que daran lugar a las
distintas especicaciones del contenido del registro Especicacion1, Especi-
cacion2,... La enumeraci on de las opciones no acaba con un End; por que
existe la restriccion de que las variantes se han de colocar en la ultima parte
de la denicion de un registro y por tanto acaban con el End; del n de la
denicion del registro.
Como ejemplo de la utilizaci on de los registros con variante vamos a con-
siderar el caso visto anteriormente de la base de datos de alumnos. Suponga-
mos que en el campo de la nota podemos querer guardar en alguna ocasion
en vez de un dato Real una calicaci on global como Aprobado y elegimos
para ello un dato String. Una posibilidad es la siguiente modicaci on del
caso anterior:
Program Nueve;
Type
Fecha =
Record
mes : 0 .. 12; { 0 seria para indicar que no se conoce la fecha}
dia : 1 .. 31;
agno : Integer ;
End;
Alumno =
Record
nombre : String;
apellidos : String;
nacimiento : Fecha;
Case final : Boolean Of
False : ( nota : Real );
True : ( notaFinal : Real;
calificacion : String[14] );
End;
Var
uno,otro : Alumno ;
Begin
.........................................
122 CAP

ITULO 9. DATOS CON ESTRUCTURA


Instrucciones validas de este programa seran tanto
uno.nota:= 6.8 ;
como,
uno.calificacion := Notable;
y al programador le queda toda la responsabilidad de utilizar una u otra.
Realmente, esta estructura del PASCAL no es muy feliz en el sentido de que
el compilador no verica el valor de la variable que da acceso a las variaciones
en los campos y su gura es meramente recordatoria para el programador.
Sea cual sea el valor de la variable utilizada para la bifurcacion del tipo
de dato, se puede acceder a la informaci on almacenada en el registro con
cualquiera de las variantes. Es responsabilidad exclusiva de programador
utilizar cada campo cuando esta denido. Con las Uniones libres se hace
mas explcito que la utilizaci on de los campos alternativos es pura respon-
sabilidad del programador y no se indica identicador para la variable que
gobierna las opciones. Para denir una Union Libre dentro de la denicion
de la estructura Record se especica la alternativa del modo siguiente:
Case
TipodeDato Of
caso1 : ( Especicacion1 );
caso2 : ( Especicacion2 );
. . .
donde caso1, caso2,... son valores posibles del tipo de dato especicado Ti-
podeDato. Es equivalente a un Registro con variante en el que se omite el
identicador de la variable que gobierna las distintas alternativas.
Esta posibilidad de acceso variable al contenido de un registro es coherente
con lo resumido anteriormente sobre el sentido de variables y tipos de datos.
El compilador reserva para el dato en la memoria un espacio suciente para
almacenar aquella de las variantes del registro de mayor tama no. Se rellenara
el espacio de memoria del modo que en cada momento desee el programador y
la eleccion se realiza usando un campo u otro. Igualmente, la interpretaci on
de los bits almacenados en esas posiciones de memoria tambien depende
del campo del registro que se utilice, en el caso de que distintos campos
correspondan a distintos tipos de datos.
9.6. UNIONES 123
Las Uniones Libres han de usarse con precaucion para evitar confusio-
nes en la lectura de los programas, pero a veces son las adecuadas para hacer
un programa legible. En el siguiente ejemplo la union entre el tipo de dato
Char y Byte se utiliza para escribir una funcion que convierte un caracter
en el correspondiente n umero de orden ASCII.
Program Diez;
Var
dato : Char;
Function ElAscii ( x : Char ) : Byte;
Type
Atomo =
{ Union libre de un Char con un Byte }
Record
Case Integer Of
1 : ( car : Char);
2 : ( num : Byte );
End;
Var
y : Atomo;
Begin
y.car := x;
ElAscii := y.num
End;
Begin { Diez }
Readln (dato);
Writeln ( El caracter ,dato , corresponde al ASCII numero : ,
ElAscii(dato) );
End. { Diez }
En la funcion ElAscii el tipo de dato Atomo se dene como la union libre
de un Char y un Byte. En este caso, ambos tipos de datos ocupan el
mismo espacio en memoria ( un byte ). La variable y ocupa pues un byte
124 CAP

ITULO 9. DATOS CON ESTRUCTURA


de memoria, pero la sucesion de bits que lo componen puede interpretarse o
bien como un Char o un Byte, dependiendo de como se referencie.
Captulo 10
Ficheros
La entrada y salida de datos desde un programa no tiene porque realizarse
utilizando los dispositivos estandard de entrada y salida (teclado y terminal),
sino que puede realizarse a traves de cualquier periferico. Tambien es posible,
y de hecho es lo mas frecuente, utilizar los dispositivos de almacenamiento
intermedio de datos. Estos dispositivos de almacenamiento de datos reciben
el nombre de archivos o cheros. Se trata generalmente de porciones de discos
magneticos donde se guarda informaci on y se identican con un nombre cuyo
formato depende del sistema operativo.
10.1 Ficheros con Tipo
Para poder referir todas las entradas y salidas, el PASCAL utiliza un tipo de
dato que se denomina File. Con este tipo de dato se pueden direccionar las
entradas y salidas de los programas a impresoras, dispositivos auxiliares,...
y tambien a archivos. El valor de un dato del tipo File es esencialmente
una direccion a donde se debe dirigir la UCP para transferir datos. El va-
lor concreto es irrelevante para el programador puesto que las instrucciones
que a el se reeren nunca requieren conocerlo. El PASCAL provee un pro-
cedimiento que permite asignar a una variable del tipo File la direccion del
dispositivo de entrada o salida que el programador pretende utilizar. Este es
el procedimiento Assign que tiene dos argumentos. El primero es el nombre
de la variable denida del tipo File y el segundo es un dato tipo String que
contiene el nombre con el que el sistema operativo identica el chero que se
quiere utilizar. En la instruccion {3} del programa Uno se especica que
125
126 CAP

ITULO 10. FICHEROS


con la variable almacen nos referimos al archivo que el sistema operativo
reconoce como Uno.sal . La variable almacen se ha declarado como File
of Byte. En la declaraci on se especica que los datos que se van a leer o
escribir en ese dispositivo son del tipo Byte.
Program Uno;
Var
almacen : File of Byte;
num1,num2,num3,num4 : Byte;
Begin
{1} num1 := 72; num2 := 79;
{2} num3 := 76; num4 := 65;
{3} Assign(almacen,uno.sal);
{4} Rewrite(almacen);
{5} Write(almacen,num1,num2);
{6} Write(almacen,num3,num4);
{7} Close(almacen)
End.
El tipo de dato que va a intercambiarse con un dispositivo especicado con
una variable del tipo File puede ser tanto basico del PASCAL o denido por
el usuario. La transferencia de datos que se puede realizar es tanto entrada
como salida. Para la salida se utilizar a el procedimiento Write y para la
entrada el Read. Ambos procedimientos tendran un argumento extra, siem-
pre el primero, que es la variable del tipo File que contiene la identicacion
del periferico al que nos referimos. Por ejemplo, en la instruccion {5} se es-
criben los valores almacenados en num1 y num2 en el periferico identicado
con almacen, es decir en el archivo uno.sal .
En el programa Uno tambien aparecen las llamadas a dos procedimien-
tos: Rewrite y Close, relacionados con las tareas que se realizan en un
ordenador para transferir datos. Con el primero se especica que el dispo-
sitivo identicado con almacen se va a utilizar para salida de datos. Esta
orden implica la realizacion de tareas que dependen del tipo de dispositivo al
que nos estamos reriendo. En el caso de archivos se ha de proceder a crear
el archivo. Cuando el dispositivo se va a utilizar como entrada de datos, las
inicializaciones necesarias se realizan con el procedimiento Reset que tam-
bien tiene como argumento la variable del tipo File que se quiere inicializar.
Tambien se utiliza Reset para salida de datos a archivos que ya existen.
10.1. FICHEROS CON TIPO 127
Cuando se acaba de transferir los datos del programa a un archivo hay
que realizar tareas simetricas a las que se realizaron en la inicializacion y que
van dirigidas a liberar el archivo del control ejercido por el programa. En
la instruccion {7} del programa uno se procede a realizar esta liberacion
con el procedimiento Close, que cierra el canal de comunicacion abierto
anteriormente con el procedimiento Reset o Rewrite.
En todo programa que se realiza una entrada o salida de datos a un dis-
positivo que no es el estandard se han de incluir las ordenes correspondientes
a la asignaci on de dispositivo, inicializacion y cierre. El esquema siempre es
Var
. . .
identicador File Of TipoDato
. . .
Begin
. . .
Assign( identicador, FichString);
. . .
Rewrite( identicador) { caso de arch. nuevo }
{ o Reset( identicador) (* caso de arch. existente *) }
. . .
Close( identicador)
En un mismo programa se puede leer y escribir utilizando diferentes disposi-
tivos y el n umero maximo de archivos que se pueden estar utilizar al mismo
tiempo esta impuesto por el sistema operativo y no por el lenguaje PASCAL
. Las palabras Rewrite y Reset tienen su origen en el uso de los dispo-
sitivos antiguos de almacenamiento intermedio de informaci on, que todava
se utilizan hoy en da. Fundamentalmente se trataba de cintas magneticas
que el operador deba o bien poner al principio para ser ledas ( Reset ),
o bien poner al principio y a nadir el anillo que por seguridad era necesario
para poder escribir en una cinta ( Rewrite ).
Cuando se escriben datos en un archivo, la informaci on se escribe exac-
tamente del mismo modo que se almacena en la memoria del ordenador. Por
ejemplo, el dato del tipo Byte 7, se escribira como la secuencia de ceros
y unos 00000111. Por tanto, cuando se lee un dato, se pueden almacenar
directamente en memoria, sin ninguna traducci on, los bits ledos. En la de-
nicion del identicador de la variable del tipo File, el tipo de datos que
se van a transferir se especica, y esta informaci on la utiliza el compilador
128 CAP

ITULO 10. FICHEROS


para vericar que no se procede a la lectura o escritura de datos de tipos dis-
tintos al anunciado en la declaraci on. Por supuesto, es responsabilidad del
programador leer apropiadamente los bits almacenados en un archivo. Por
ejemplo, si la informacion escrita en una archivo declarado como File Of
Byte se lee en otro programa distinto declarando el archivo como File Of
Char se obtendra una traduccion de n umeros enteros a los caracteres ASCII
correspondientes. Exactamente lo contrario se consigue si el programa dos
utiliza el mismo archivo uno.sal escrito con el programa Uno como entrada
de datos.
Program Dos;
Var
almacen : File of Char;
num1,num2,num3,num4 : Char;
Begin
Assign(almacen,uno.sal);
Reset(almacen);
Read(almacen,num1,num2);
Read(almacen,num3,num4);
Close(almacen);
Writeln(num1,num2,num3,num4);
End.
La salida del programa dos es :
HOLA
Exactamente el mismo saludo es el que se puede leer en el chero uno.sal
cuando se edita con un editor de cheros ASCII como el del Entorno Integrado
de Desarrollo del TURBO PASCAL .
Un dispositivo de entrada-salida se puede denir como File Of cualquier
tipo de dato, incluyendo los denidos por el usuario. Son especialmente utiles
los archivos del tipo registro, pues en ellos se pueden almacenar facilmente
datos con la estructura interna requerida por el usuario. Por ejemplo, en el
problema esbozado en el tema anterior sobre una base de datos con infor-
macion sobre alumnos, el mantenimiento de dicha base podra proceder del
siguiente modo:
Program Tres;
10.1. FICHEROS CON TIPO 129
{ Utilidad para actualizar el archivo de alumnos }
{ Solo sirve para agnadir uno nuevo }
Type
Fecha =
Record
mes : 0 .. 12; { 0 seria para indicar que no se conoce la fecha}
dia : 1 .. 31;
agno : Integer ;
End;
Alumno =
Record
nombre : String;
apellidos : String;
nacimiento : Fecha;
End;
Var
carpeta : File of Alumno;
uno,otro : Alumno ;
respuesta,c : Char;
nomArchi : String;
Begin { Tres }
nomArchi := Archi.dat;
Writeln(Nombre : ) ; Readln(uno.nombre);
Writeln(Apellidos : ); Readln(uno.apellidos);
Writeln(A~ no de nacimiento : ); Readln(uno.nacimiento.agno);
Writeln(Mes de nacimiento: ); Readln(uno.nacimiento.mes);
Writeln(Dia de nacimiento: ); Readln(uno.nacimiento.dia);
Writeln(Desea incorporalo a la base de datos ? (s/n) :);
Readln(respuesta);
If (respuesta = s) Or (respuesta = S) Then
Begin
Assign(carpeta,nomArchi);
Reset(carpeta);
While Not Eof(carpeta) Do Read(carpeta,otro);
Write(carpeta,uno);
Close(carpeta);
130 CAP

ITULO 10. FICHEROS


End; {endif}
End. { Tres }
En este programa se utiliza la funcion Eof que tiene como argumento la
variable del tipo File carpeta. Esta es una funcion del tipo Boolean que
devuelve el valor True si se alcanzado el n del chero al que apunta su
argumento. La funcion se utiliza en el programa Tres para recorrer todo el
archivo hasta el nal y despues a nadir el nuevo registro.
El listado de todos los alumnos incluidos en la base de datos se podra
realizar mediante el siguiente programa:
Program Cuatro;
{ Utilidad para listar el archivo de alumnos }
Type
Fecha = Record
mes : 0 .. 12;
dia : 1 .. 31;
agno : Integer ;
End;
Alumno = Record
nombre : String;
apellidos : String;
nacimiento : Fecha;
End;
Var
carpeta : File of Alumno;
uno : Alumno ;
nombreCarpeta : String;
Begin { Cuatro }
Writeln( Nombre del archivo donde se almacenan : );
Readln(nombreCarpeta);
Assign(carpeta,nombreCarpeta);
Reset(carpeta);
While Not Eof(carpeta) do begin
Read(carpeta,uno);
With uno Do
Begin
Write(apellidos,, ,nombre);
10.2. PROCESAMIENTO SECUENCIAL Y ALEATORIO 131
If nacimiento.mes <> 0 Then
Writeln( (,nacimiento.dia,/,nacimiento.mes,/,
nacimiento.agno,));
End
End; {endwhile}
Close(carpeta);
End. { Cuatro }
10.2 Procesamiento secuencial y aleatorio
Tanto en el programa Tres como en el Cuatro se esta realizando un proce-
samiento secuencial de los archivos. Se inicia la lectura por el primer registro
y se procede hasta llegar al deseado o al nal. En el caso del programa
Tres este tipo de procesamiento ha obligado, para llegar hasta el ultimo de
los registros, a transferir a memoria el contenido de todos los registros. La
estructura interna de un archivo es lineal y muy parecida a la estructura
Array del PASCAL . Por tanto, debera ser posible acceder a los diferentes
registros sin necesidad de leerlos a la memoria RAM. Esta posibilidad es la
que permite el procedimiento del PASCAL Seek que tiene dos argumentos:
el primero un dato tipo File, y el segundo LongInt. El efecto de esta fun-
cion es preparar el archivo identicado por el dato File para la lectura o
escritura a partir del n umero de registro que contiene la variable LongInt.
De hecho, dado que los registros se empiezan a contar con el 0, se colocara
pasado el registro indicado por el n umero LongInt. Por ejemplo, si fichero
se dene como File Of Integer, la llamada Seek (fichero, 23) har a que
la siguiente lectura realizada sobre fichero transera a la memoria del or-
denador el dato Integer con el n umero de orden 24; se han saltado 46 bytes
del chero.
Con la posibilidad brindada por el procedimiento Seek se puede realizar
lo que se llama procesamiento aleatorio de cheros. A pesar del nombre,
esto no tiene nada que ver con el azar, sino que implica leer o escribir en
archivos en un orden distinto que el secuencial. Para explicar la utilidad y
servidumbres de este tipo de procesamiento, vamos a modicar el dise no de
la base de datos de alumnos sugerida anteriormente. El objetivo es colocar
al principio del chero un n umero que nos indique la cantidad de alumnos
incluidos en la lista.
Program IniciaLista;
132 CAP

ITULO 10. FICHEROS


{ Utilidad para inicializar una lista de alumnos }
Type
Fecha =
Record
mes : 0 .. 12; dia : 1 .. 31; agno : Integer ;
End;
Alumno =
Record
Case Boolean of
True : ( nombre : String;
apellidos : String;
nacimiento : Fecha );
False :
( numeroTotal : Integer );
End;
Var
carpeta : File of Alumno;
otro : Alumno ;
nomArchi : String;
Begin { IniciaLista }
Writeln(Inicializaci on de un archivo de alumnos);
Writeln(Nombre del archivo: ); Readln(NomArchi);
Assign(carpeta,nomArchi);
Rewrite(carpeta); {Se crea el archivo}
otro.numeroTotal := 0; {Se inicializa a 0 el numero de orden }
Write(carpeta,otro);
Close(carpeta);
End. { IniciaLista }
En el programa IniciaLista se procede a inicializar la base de datos: se
crea el archivo con el nombre indicado por el usuario y se escribe en el
primer registro el Integer 0 para indicar que no hay todava ning un alumno
incluido. Como almacen se tiene que denir como un File Of alumno para
poder escribir un entero en el primer registro tenemos que recurrir a una
uni on libre del registro.
El programa que puede a nadir un alumno en la base de datos es :
Program AumentaLista;
10.2. PROCESAMIENTO SECUENCIAL Y ALEATORIO 133
{ Utilidad para agnadir una alumno a una lista }
{ Solo sirve para agnadir UNO }
Type
Fecha =
Record
mes : 0 .. 12; dia : 1 .. 31; agno : Integer ;
End;
Alumno =
Record
Case Boolean of
True : ( nombre : String;
apellidos : String;
nacimiento : Fecha );
False : ( numeroTotal : Integer );
End;
Var
carpeta : File of Alumno;
uno,otro : Alumno ;
respuesta : Char;
nomArchi : String;
Begin {AumentaLista}
Writeln(Nombre del archivo: ); Readln(NomArchi);
Writeln(Nombre : ) ; Readln(uno.nombre);
Writeln(Apellidos : ); Readln(uno.apellidos);
Writeln(A~ no de nacimiento : ); Readln(uno.nacimiento.agno);
Writeln(Mes de nacimiento: ); Readln(uno.nacimiento.mes);
Writeln(Dia de nacimiento: ); Readln(uno.nacimiento.dia);
Writeln(Desea incorporarlo a la base de datos ? (s/n) :);
Read(respuesta);
If (respuesta = s) Or (respuesta = S) Then
Begin
Assign(carpeta,nomArchi);
Reset(carpeta);
Read(carpeta,otro);
Seek(carpeta,otro.numeroTotal+1); {Al final}
Write(carpeta,uno);
134 CAP

ITULO 10. FICHEROS


Seek(carpeta,0); { Al principio }
otro.numeroTotal := otro.numeroTotal + 1;
Write(carpeta,otro);
Close(carpeta);
End; {EndIf}
End. {AumentaLista}
En este programa, para llegar al nal del chero simplemente se saltan los
registros indicados al principio, y se escribe el nuevo. Despues, se vuelve al
principio para aumentar en 1 el contador de registros almacenados.
El listado de los alumnos en la base de datos sera :
Program ListaLista;
{ Utilidad para escribir el archivo de alumnos }
Type
Fecha =
Record
mes : 0 .. 12; dia : 1 .. 31; agno : Integer ;
End;
Alumno =
Record
Case Boolean of
True : ( nombre : String;
apellidos : String;
nacimiento : Fecha );
False :
( numeroTotal : Integer );
End;
Var
i : Integer;
carpeta : File of Alumno;
uno,n : Alumno ;
nombreCarpeta : String;
Begin { ListaLista }
Writeln( Nombre del archivo donde se almacenan : );
Readln(nombreCarpeta);
Assign(carpeta,nombreCarpeta);
Reset(carpeta);
Read(carpeta,n);
10.2. PROCESAMIENTO SECUENCIAL Y ALEATORIO 135
For i := 1 To n.numeroTotal Do
Begin
Read(carpeta,uno);
With uno Do
Begin
Write(i:3, ,apellidos,, ,nombre);
If nacimiento.mes <> 0 Then
Writeln( (,nacimiento.dia,/,nacimiento.mes,/,
nacimiento.agno,));
End
End; {endfor}
Close(carpeta);
End. { ListaLista }
Con esta nueva denicion de la base de datos de alumnos resulta muy sen-
cillo escribir un programa para corregir errores en alguno de los registros
almacenados.
Program ModificaLista;
{ Utilidad para modificar un alumno en la lista }
Type
Fecha =
Record
mes : 0 .. 12; dia : 1 .. 31; agno : Integer ;
End;
Alumno =
Record
Case Boolean of
True : ( nombre : String;
apellidos : String;
nacimiento : Fecha );
False : ( numeroTotal : Integer );
End;
Var
elemento :Integer;
carpeta : File of Alumno;
uno,otro : Alumno ;
136 CAP

ITULO 10. FICHEROS


Respuesta : Char;
nomArchi : String;
Begin {ModificaLista}
Writeln(Nombre del archivo: ); Readln(NomArchi);
Writeln(Numero de orden: ); Readln(elemento);
Writeln(Nombre : ) ; Readln(uno.nombre);
Writeln(Apellidos : ); Readln(uno.apellidos);
Writeln(A~ no de nacimiento : ); Readln(uno.nacimiento.agno);
Writeln(Mes de nacimiento: ); Readln(uno.nacimiento.mes);
Writeln(Dia de nacimiento: ); Readln(uno.nacimiento.dia);
Writeln(Desea incorporalo a la base de datos ? (s/n) :);
Read(respuesta);
If (respuesta = s) Or (respuesta = S) Then
Begin
Assign(carpeta,nomArchi);
Reset(carpeta);
Read(carpeta,otro);
Seek(carpeta,elemento);
Write(carpeta,uno);
Close(carpeta);
End; {EndIf}
End. {ModificaLista}
En este programa se accede directamente al registro que se quiere modicar
y el usuario lo identica con el n umero de orden que aparece en el listado.
Esta labor hubiera sido mucho mas difcil de realizar con un procesamiento
meramente secuencial del archivo.
10.3 Ficheros de Texto
Como se menciono anteriormente, el uso de cheros de un tipo de dato de-
nido, permite que la informaci on se almacene en los archivos del mismo
modo que se escribe en la memoria del ordenador. Por tanto, no es necesario
ninguna traducci on para pasarlos a la memoria RAM. La ventaja de usar
este tipo de archivos es la rapidez en la transferencia de informaci on entre
memoria RAM y dispositivos de almacenamiento. El inconveniente es la falta
10.3. FICHEROS DE TEXTO 137
de compatibilidad: para leer correctamente la secuencia de bits escrita por
un programa PASCAL en un chero con tipo es necesario u otro programa
PASCAL o un programa muy sutil en otro lenguaje que tenga en cuenta
la estructura interna de los datos PASCAL . El modo estandar actual para
transferir informaci on es utilizar el codigo de caracteres ASCII almacenados
en un byte con el bit menos signicativo a la derecha. Por tanto, si se quiere
escribir en un archivo informacion que sea legible por la mayora de las uti-
lidades que existen com unmente hoy en da hay que utilizar los datos Char
del PASCAL . Ademas tambien es estandar el modo en el que se especica
el salto de lnea.
El PASCAL suministra el tipo de chero llamado Text para denir dis-
positivos externos a los que se transere toda la informaci on traducida a
caracteres ASCII. Por ejemplo, los dispositivos estandar de entrada y sali-
da (teclado y terminal TRC) son un ejemplo de Text. Los procedimientos
Readln y Writeln, que no se podan utilizar con los cheros con tipo se
pueden utilizar con los cheros de texto y son los que se encargan de ges-
tionar los caracteres ASCII de cambio de lnea (codigos 10 y 13 del ASCII).
Un chero Text es algo mas que un File Of Char puesto que el compila-
dor se encarga de traducir las ordenes de escritura de todo tipo de datos a
caracteres ASCII y con los formatos que indique el programador.
El programa siguiente:
Program Cinco;
Var
almacen : Text;
saludo : String;
Begin
Assign(almacen,uno.sal);
Reset(almacen);
Readln(almacen,saludo);
Writeln(saludo);
Close(almacen)
End.
tiene la misma salida al terminal que el programa Dos cuando el archivo
Uno.sal es el escrito por el programa Uno. Ejemplos de manipulacion de
cheros con texto son todos los programas vistos hasta este tema puesto que
toda la entrada y salida de datos se realizaba sobre los dispositivos Input y
Output que son cheros del tipo Text.
138 CAP

ITULO 10. FICHEROS


La ventaja de portabilidad de los cheros del tipo Text es a costa de
tiempo de procesamiento y espacio de disco. Antes de pasar un dato de la
memoria a un archivo o viceversa se ha de realizar la traducci on de caracteres
ASCII. Con los dos siguientes programas:
Program Seis;
Uses Dos;
Var
almacen : File Of Real;
x : Real;
i : Integer;
h1,m1,s1,c1,h2,m2,s2,c2 : Word;
Begin
Assign(almacen,seis.sal);
Rewrite(almacen);
GetTime(h1,m1,s1,c1);
Writeln(h1,:,m1,:,s1,:,c1);
For i := 1 to 10000 Do Begin
x := Random;
Write(almacen,x);
End; {endfor}
GetTime(h2,m2,s2,c2);
Writeln(h2,:,m2,:,s2,:,c2);
Close(almacen)
End.
y,
Program siete;
Uses Dos;
Var
almacen : Text;
x : Real;
i : Integer;
h1,m1,s1,c1,h2,m2,s2,c2 : Word;
Begin
Assign(almacen,siete.sal);
Rewrite(almacen);
GetTime(h1,m1,s1,c1);
10.3. FICHEROS DE TEXTO 139
Writeln(h1,:,m1,:,s1,:,c1);
For i := 1 to 10000 Do Begin
x := Random;
Writeln(almacen,x);
End; {endfor}
GetTime(h2,m2,s2,c2);
Writeln(h2,:,m2,:,s2,:,c2);
Close(almacen)
End.
se puede comprobar la diferencia entre los dos tipos de transferencia de in-
formaci on. En el Seis se escriben los datos Real en un chero File Of
Real y en el Siete en un chero Text. El procedimiento GetTime, que se
encuentra en la unidad Dos, devuelve el tiempo en horas, minutos, segundos
y centesimas. Este procedimiento es el que se utiliza en ambos casos para
detectar el tiempo que se emplea en escribir 1000 datos Real. Con la salida
de estos dos programas se puede comprobar que el segundo programa emplea
casi el doble de tiempo que el primero en escribirlos. As mismo, el archivo
Siete.sal que se crea ocupa casi tres veces el espacio ocupado por el chero
Seis.sal. Este ultimo, solo ocupa 60000 bytes puesto que cada Real esta
formado por 6 bytes, y Siete.sal ocupa 190000 bytes puesto que se necesitan
19 caracteres ASCII para describir con el formato estandard cada dato Real
(17 para el n umero y 2 para el salto de lnea).
Otra desventaja adicional de los cheros de texto es que solo aceptan
procesamiento secuencial y NO aleatorio.
140 CAP

ITULO 10. FICHEROS


Captulo 11
Punteros y asignacion dinamica
de memoria
11.1 Contenidos, direcciones e identicado-
res
Hasta ahora hemos considerado que los datos almacenados en la memoria
pueden accederse a traves del nombre de variables y constantes. Asumimos
que el nombre de la variable es el indicador que permite al compilador de-
terminar a que dato nos referimos y generar codigo UCP para operar con el.
Cada dato esta almacenado en una posicion de memoria y su contenido se
puede modicar a traves de la relacion unvoca que existe entre el nombre
de la variable y la posicion que el dato ocupa en la memoria del ordenador.
Consideremos un programa tan sencillo como el siguiente:
Program Uno;
Var
a , b : Integer;
Begin { Uno }
{1} Readln(a);
{2} b := a;
{3} Writeln(a:4, ,b:4);
End. { Uno }
en el que se denen las variables a y b para almacenar datos del tipo In-
teger. En la instruccion {3} se especica que el dato almacenado en la
141
142 CAP

ITULO 11. PUNTEROS


posicion de memoria a la que nos referimos con la variable a ha de alma-
cenarse tambien en la posicion de memoria a la que nos referimos con la
variable b.
11.2 Punteros
En ning un momento se ha hecho explicito en la sintaxis del lenguaje que un
dato esta identicado internamente por una posicion de memoria. Sin em-
bargo, es muy util poder manipular los datos realizando algoritmos en los que
tambien interviene la direccion de los datos. Para ello el PASCAL permite
que en los programas aparezca un tipo de dato que son las direcciones de los
datos. Estas direcciones se llaman normalmente punteros, y en un programa
PASCAL pueden intervenir las direcciones de datos que esten denidos. Se
especica que una variable es un puntero a un tipo de dato con la ayuda del
calicador que se antepone a un identicador.
El dato ^tipodato es el puntero a un dato del tipo tipodato. Por
ejemplo en el segmento de programa :
Type
Fecha =
Record
dia : Integer;
mes : Integer;
End;
Var
a: Integer;
px : ^Real;
pa : ^Integer;
pHoy,pAyer : ^Fecha;
. . .
se esta declarando que px es un puntero a un dato Real, pa un puntero
a un Integer, y pHoy y pAyer punteros a registros de Fecha. El mismo
calicador sirve para especicar que queremos utilizar el dato almacenado
en la direccion de memoria especicada por el puntero, pero esta vez se a nade
al nal del identicador. Por ejemplo, cuando aparece en una parte posterior
del programa citado anteriormente pHoy^ estamos indicando el contenido
del registro del tipo fecha apuntado por el puntero pHoy. La asignaci on
11.2. PUNTEROS 143
. . .
pHoy^ := pAyer^;
. . .
implica que se almacene en el lugar de memoria indicado por pHoy el dato
almacenado en el registro al que apunta pAyer. Para completar la herra-
mienta es necesario un operador que sea capaz de extraer de una variable su
direccion, y este es el operador que se representa por @. La asignaci on:
pa := @a;
es correcta porque pa es el puntero a un Integer y el resultado de operar @
sobre a (que es un Integer ) es tambien el puntero a un Integer.
Una version sosticada del programa Uno es la siguiente:
Program Dos;
Var
a ,b : Integer;
pb : ^Integer;
Begin { Dos }
{1} a := 10 ;
{2} pb := @a ;
{3} b := pb^ ;
{4} Writeln(a:4, ,b:4);
End. { Dos }
en la que se obtiene exactamente el mismo resultado que en Uno pero con
el uso explcito de direcciones de variables. La variable pb es un puntero a
un Integer, es decir la direccion de un dato Integer, y en la instruccion
{2} se determina que es exactamente la misma que la de la variable Integer
a. En la instruccion {3} se asigna a la variable b el dato almacenado en
la direccion que habamos almacenado en el dato ( puntero ) pb. El dato
almacenado en b sera pues el mismo que el almacenado en a. Las instruc-
ciones {3} y {4} de programa Dos producen el mismo resultado que la {2}
del programa Uno recorriendo un camino mas largo y con una sintaxis me-
nos clara. Pero si este tipo nuevo de dato se introduce en el lenguaje no es
para hacer complicado lo sencillo, sino para aumentar las posibilidades del
lenguaje tal como comentaremos en este tema.
Antes de seguir adelante puede ser ilustrativo considerar el siguiente pro-
grama,
144 CAP

ITULO 11. PUNTEROS


Program Tres;
Var
a : String;
pa,pb : ^String;
Begin { Tres }
a := Hola; { en a se almacena Hola }
pa := @a; { pa apunta a}
pb:= pa; { pb apunta a}
writeln(a);
pb^ := Adios;
Writeln(a); { el contenido de a es Adios }
End. { Tres }
en el que se modica el valor del String a indirectamente a traves del con-
tenido del puntero pb. Las direcciones de memoria que se almacenan en
los datos del tipo puntero, dependeran de cada tipo de ordenador, y en ge-
neral, el programador puede olvidarse de esos detalles, pues solo utilizara
los punteros para manipular los datos a los que apuntan y evitara asignar
directamente valores numericos a los punteros. Generalmente se asigna a un
puntero el contenido de otro. Hay una excepcion: se trata del valor Nil, ya
que no corresponde a un lugar de memoria y se utiliza para identicar que un
puntero no apunta a ning un lugar de la memoria. A un puntero, apuntando
a cualquier tipo de dato, siempre se le puede asignar el valor Nil.
Las operaciones que se pueden realizar con los punteros, son asignar y
comparar por igualdad o desigualdad. Con estas comparaciones se puede
discernir la equivalencia de direcciones. Sin embargo, no se pueden comparar
los punteros con los operadores > y <.
Vamos a vericar el motivo de llamar argumentos por referencia o direc-
cion a los argumentos antecedidos por Var en las funciones y procedimientos.
La salida del programa Cuatro,
Program Cuatro;
Type pinte = ^Integer;
Var
a ,b ,c: Integer;
11.3. ASIGNACI

ON DIN

AMICA DE MEMORIA. 145


Procedure Cuacua ( x : pinte;
y : Integer;
Var z : Integer
);
Begin
x^ := x^ * x^;
y := y * y ;
z := z * z ;
End;
Begin { Cuatro }
a := 2 ;
b := 3 ;
c := 4 ;
Cuacua(@a,b,c);
Writeln(a:6, ,b:6, ,c:6);
End. { Cuatro }
es,
4 3 16
El valor de la variable b no se modica como resultado de la llamada a la
funcion porque es una argumento pasado por contenido. La variable c se
modica porque se pasa por referencia, y la variable a tambien modica su
valor porque el argumento es la direccion de a y por tanto en la funcion de
puede modicar el contenido de esa direccion.
11.3 Asignaci on dinamica de memoria.
Una utilidad de los punteros es poder crear programas que ocupen la can-
tidad de memoria del ordenador adecuada a cada caso seg un se determina
durante la ejecucion del programa. Cuando un programa se va a ejecutar, se
carga en la memoria del ordenador y la memoria ocupada por el programa
esta estructurada en varias partes o segmentos. El codigo para la UCP se
carga en memoria en el llamado segmento de codigo. Los datos denidos
en el programa se cargan en el llamado segmento de datos, y hay un tercer
segmento llamado pila (stack) que se reserva para los datos que se han de
146 CAP

ITULO 11. PUNTEROS


manipular temporalmente durante la ejecucion del programa, por ejemplo,
para almacenar los valores de las variables que se han de crear para reali-
zar un procedimiento. El resto de la memoria se gestiona como un monton
(heap) y tambien puede estar disponible para el programa.
La funcion New es la que gestiona la captaci on para el programa de la
memoria del monton. El argumento de la funcion ha de ser un puntero a
un tipo de dato del PASCAL o denido por el programador, y la funcion
New asigna a ese puntero el valor de una direccion de memoria del monton
con el tama no adecuado para almacenar un dato del tipo al que apunta
su argumento. En el momento en el que esa porcion de memoria ya no
sea necesaria para el algoritmo codicado en el programa, puede liberarse
del control del programa con la funcion Dispose, que tiene por argumento
el puntero donde se almacena la direccion de la porcion de memoria que
se quiere liberar. A esta gestion de la memoria del ordenador durante la
ejecucion del programa se le llama asignaci on dinamica de la memoria.
El programa Cinco es una modicacion del Tres en el que la memoria
utilizada para almacenar los saludos no esta en el segmento de datos sino en
el Heap.
Program Cinco;
Var
pa,pb : ^String;
Begin { Cinco }
New(pa);
pa^ := Hola;
pb:= pa;
writeln(pa^);
pb^ := Adios;
Writeln(pa^);
Dispose(pb);
End. { Cinco }
Se reserva la memoria con New antes de almacenar ning un valor en esa
direccion. La ultima instruccion hubiera igualmente podido ser Dispose(pa)
porque ambos punteros almacenan la misma direccion de memoria que se
libera con Dispose. Es mas, la siguiente modicacion es incorrecta por
varios motivos.
11.4. DECLARACIONES RECURSIVAS DE TIPOS DE DATOS 147
Program CincoIncorrecto;
Var
pa,pb : ^String;
Begin { Incorrecto }
New(pa);
pa^ := Hola;
New(pb);
pb:= pa;
writeln(pa^);
pb^ := Adios;
Writeln(pa^);
Dispose(pb);
Dispose(pa);
End. { Incorrecto }
Primero, el programa dara un error en la ejecucion. La ultima instruccion
intenta liberar un lugar de memoria que ya ha sido liberado en la llamada an-
terior a Dispose. Por otra parte, es un ejemplo claro de mal uso de la gestion
dinamica de memoria. La memoria reservada para el programa mediante la
tercera instruccion (256 bytes) no se puede liberar puesto que hemos perdido
la pista de cual era. Es una practica poco recomendable escribir programas
que cuando acaban dejan sin liberar memoria que reservaron del mont on.
11.4 Declaraciones recursivas de tipos de da-
tos
La asignaci on dinamica de memoria permite crear estructuras de datos que
pueden crecer y disminuir seg un los requerimientos que el programa detecta
durante la ejecucion. La mas sencilla de ellas es la llamada lista unida. Me-
diante denicion de punteros a datos en la memoria y uniendolos entre ellos,
se obtienen listas de objetos sin tama no especco. Pueden ser listas vacas
o contener miles de datos, crecer y menguar durante la ejecucion del progra-
ma. Son estructuras de datos recursivas que se comprenden facilmente con
esquemas, pero primero veremos un ejemplo de como se denen en PASCAL
.
Type
148 CAP

ITULO 11. PUNTEROS


Enlace = ^Nodo;
Nodo =
Record
clave : Integer;
siguiente : Enlace
End;
Primero se dene el puntero Enlace como la direccion a un dato (todava
sin denir) Nodo y despues se declara cual es el signicado del tipo de dato
Nodo. Este es un registro que en su primer campo puede almacenar un
entero y en el segundo un puntero, Enlace, a un dato del mismo tipo Nodo.
La recursividad esta obviamente en la autorreferencia durante la denicion.
Merece la pena destacar que el caso de los punteros es unico en el PASCAL
en cuanto a que es posible denir un tipo de dato a partir de otro que
todava no esta denido. Esta exibilidad es necesaria para poder generar la
recursividad.
Las variables del tipo Nodo van a ser los ladrillos con los que se construir a
una lista unida de n umeros enteros. Cada uno de ellos puede almacenar un
n umero entero y la direccion del siguiente en la lista.
La lista mas peque na que podemos tener es de un solo elemento. Para
identicar que nadie le sigue podemos recurrir al valor Nil.
Nodo Nodo Nodo

Nil
Enlace
El dibujo es muy ilustrativo de la estructura de datos llamada lista unida.
Cada elemento de la lista puede almacenar informaci on relevante para el
11.4. DECLARACIONES RECURSIVAS DE TIPOS DE DATOS 149
problema en la que se utiliza y tambien el enlace con el siguiente vag on.
Para cada elemento de la lista habr a que reservar memoria, tanto para la
informaci on que se quiere guardar, como para el puntero que sirve de enlace.
Vamos a utilizar en el programa Seis una lista unida para almacenar
en la memoria del ordenador cuantos n umeros enteros teclee el usuario para
poder luego listarlos en el orden inverso al que se teclearon. La memoria del
ordenador que necesitara el programa Seis para ejecutarse dependera de los
n umeros que se tecleen. Si son unos pocos sera muy poca la memoria que
tomar a, y, el lmite superior de n umeros que se pueden teclear dependera de
la memoria RAM instalada en el ordenador. Si en vez de una lista unida
hubieramos utilizado una estructura Array para almacenar los enteros, la
memoria debera determinarse al escribir en el programa el rango de variaci on
del ndice del Array.
Program Seis;
Type
enlace = ^Nodo;
Nodo =
Record
clave : Integer;
siguiente : Enlace
End;
Var
y,z : enlace;
i : Integer;
Begin
{ Se inicializa la lista }
New(z);
z^.siguiente := Nil; {El ultimo elemento apunta a Nil}
{Se leen los datos y se incluyen en la lista }
Readln(i);
While i >= 0 Do { Un numero negativo finaliza el proceso}
Begin
New(y);
y^.clave := i;
150 CAP

ITULO 11. PUNTEROS


y^.siguiente := z;
z := y;
Readln(i)
End;
{Se escribe la lista}
While (y^.siguiente <> Nil ) Do
Begin
Writeln(y^.clave) ;
z := y^.siguiente;
Dispose(y);
y := z;
End;
Dispose(z)
End.
Para detectar el nal de la lista, recurrimos a la direccion Nil. Cuando reco-
rremos la lista para escribir el contenido, nos detenemos cuando un nodo (el
ultimo) apunta a esa constante. No hay que olvidar nunca reservar memoria
del Heap para cada elemento nuevo de la lista. De lo contrario, se pueden
obtener resultados impredecibles. Cuando se escribe informacion en la direc-
cion de memoria dictada por un puntero que no ha sido convenientemente
inicializado estaremos escribiendo en un lugar descontrolado y los resultados
son imprevisibles. Dado que los n umeros tecleados por el usuario se van incor-
porando a la lista seg un se teclean, y no guardamos la pista sobre donde esta
el primer elemento almacenado en memoria, solo podemos listar los n umeros
en el orden inverso al que fueron tecleados. Para listar los n umeros en el
mismo orden en el que fueron tecleados existen varias posibilidades pero su
analisis queda fuera de los objetivos de este curso. Sin ahondar mucho mas
en las estructuras de datos que se pueden generar con los punteros merece la
pena resaltar la simplicidad y eciencia de cierta operaciones que se realizan
com unmente sobre listas unidas. El insertar un nuevo elemento en el lugar
elegido de la lista puede ser algo tan sencillo como :
{un nuevo nodo se crea a continuacion del apuntado por y}
New(z);
z^.clave := i;
z^.siguiente := y^.siguiente;
y^.siguiente := z;
11.4. DECLARACIONES RECURSIVAS DE TIPOS DE DATOS 151
y la eliminacion de un nodo :
{Se elimina el nodo a continuacion del apuntado por y}
z:= y^siguiente;
y^.siguiente := y^.siguiente^.siguiente ;
Dispose(z);
Estructuras de datos como listas doblemente unidas, circulares y arboles, son
muy comunes en la realizaci on de algoritmos ecientes.
A estas alturas del curso podemos entender perfectamente el programa
llamado Josefo que se estudio en el Tema 3. No obstante, el alumno no
debe esperar que con los conocimientos sobre programaci on adquiridos hasta
ahora debera haber dise nado un programa similar a Josefo para resolver
el problema. Tales dise nos no aparecen generalmente por intuicion sino co-
mo resultado del estudio de las estructuras de datos y algoritmos que se
han desarrollado para diferentes problemas tipo planteados a la ciencia de
la computaci on. El objetivo de esta parte del curso era que el alumno com-
prendiera un programa como el citado y sobre todo que en los programas que
escriba, sean los problemas que resuelvan mas o menos sencillos, utilice la
herramientas aprendidas siguiendo las normas de claridad y estilo referidas
continuamente.

You might also like