You are on page 1of 19

Contenido

I. Estructura de un programa
II. Manejo de la información
____Tipos de datos
____Variables
____Constantes
____Asignación
____Tipos de datos definidos por el usuario
____Ingreso e impresión de datos por pantalla
____Inicialización de variables
III. Estructuras de control
____Estructuras selectivas
________1. IF – THEN – ELSE
________2. CASE
____Estructuras iterativas
________1. FOR
________2. WHILE
________3. REPEAT
IV. Modularización
____Funciones
____Procedimientos
____Parámetros por valor
____Parámetros por referencia
V. Otros tipos de datos compuestos definidos por el usuario
____Vectores
____Matrices
____Conjuntos
____Registros
____Vectores de registros
VI. Algunas funciones y procedimientos para trabajar con strings
____LENGTH
____POS
____COPY

I. Estructura de un programa
Un programa está compuesto por diversos bloques de código, algunos de ellos opcionales y
otros de existencia obligatoria:
1. Cabecera: indica el nombre del programa sólo a modo de título o información. El
nombre del archivo que contiene el programa puede no ser el mismo. El nombre del
programa debe comenzar con una letra o un guión bajo, anteponiéndose la palabra
reservada “program” y finalizando la línea con un punto y coma.
2. Declaración de unidades: para el caso de que el programa requiera de la utilización de
unidades externas, con el fin de adicionar funciones a las predefinidas de turbo pascal. La
palabra reservada es “uses”, seguida del nombre del archivo que refiere a la unidad.
3. Declaración de constantes: la palabra reservada para declarar una constante es “const”,
seguida por el identificador de dicha constante, el cual debe comenzar con una letra o un
guión bajo, un signo de igualdad (=) y el valor de la constante.
4. Declaración de tipos: sector en el cual se definen nuevos tipos de datos. La palabra
reservada es “type”, seguida del nombre del tipo, un signo de igualdad (=) y la definición.
5. Declaración de variables globales: generalmente no utilizadas. Afectan a todo el
programa.
6. Declaración de módulos: también llamados “subprogramas” o “subrutinas”. Todos los
módulos y funciones deben implementarse antes de ser utilizados. Es decir, si un módulo
invoca a otro, el código de este último deberá estar situado en una posición anterior a la
invocación. Esto es debido a que el compilador de Pascal interpreta el código en orden,
comenzando por la primera línea.
Un módulo puede contener declaración de variables locales (sólo existen dentro de él).
Comienzan con la palabra “begin” y finalizan con “end;” (el punto y coma indica que el
programa continúa).
7. Declaración de variables: justo antes de comenzar el cuerpo del programa principal,
deben definirse las variables que se van a utilizar en él. Se indican con la palabra “var”
seguida del nombre de la variable y el tipo de dato que representa.
8. Cuerpo del programa: el programa principal debe estar encerrado entre las etiquetas
“begin” y “end.” (el “end” final va seguido de un punto).
II. Manejo de la información
Tipos de datos
La información representada en el programa constituirá los “datos” con los que se deberá
trabajar.
Pascal es un lenguaje de programación fuertemente tipado, lo que significa que siempre
debe indicársele con qué clase de datos está tratando -por ejemplo: números, letras, valores
lógicos, etc.-, ya que, como sabemos, para la computadora todo es un gran conjunto de unos
y ceros, y necesita saber qué es lo que esos dígitos binarios están representando.
Por lo tanto, un tipo de dato indicará al compilador cuáles son los valores posibles que
contendrá ese dato y, además, qué operaciones se puede realizar con ellos.
Diferentes lenguajes de programación pueden tener la capacidad de representar diferentes
tipos de datos. Pero existen algunos básicos que, generalmente, se encuentran en todos
ellos:
• Integer: representa números enteros, positivos o negativos. En Pascal, este tipo de dato
ocupa 2 bytes en memoria (16 bits), por lo que es posible representar 65.536 (216) números
diferentes. Como se abarca tanto negativos como positivos, el rango va desde -32.768 hasta
32.767 (se incluye el 0). Es un tipo de dato ordinal, es decir que para cada valor existe un
antecesor y un sucesor (el 2 es sucesor del 1 y antecesor del 3).
• Real: para números reales (con decimales), positivos o negativos. En Pascal cada dato de
tipo real ocupa 6 bytes, y pueden tomar valores en el rango de 2.9 x 10-39 to 1.7 x 1038
números positivos y lo mismo para negativos. La parte entera de un número se separa de la
parte decimeal por medio de un punto (por ejemplo, 247.50). Es un tipo de dato no ordinal,
ya que al poder adoptar infinitos valores debido a los decimales, no se puede decir cuál es
el antecesor y cuál el sucesor.
• Boolean: ocupa 1 byte y puede tomar sólo valores lógicos. Es decir, el dato contiene
“true” (verdadero) o “false” (falso). Es un tipo de dato ordinal (False equivale a 0 y True
equivale a 1, por lo tanto, False es antecesor de True).
• Char: permite representar un caracter de la tabla ascii. Ocupa 1 byte en memoria. Los
caracteres se representan entre comillas simples. Por ejemplo: ‘m’. Es un tipo de dato
ordinal, ya que cada caracter tiene un valor numérico asociado en la tabla ascii.
• String: representa una cadena de caracteres (con un máximo de 256). El tamaño ocupado
en memoria varía entre 1 y 255 bytes. Si no se aclara el espacio a reservar, por defecto
ocupa 255 bytes. Si se indica el espacio máximo que puede adoptar la variable, ésta
ocupará esa cantidad de bytes en memoria, se utilicen o no. Los strings, al igual que los
caracteres, se representan entre comillas simples. Por ejemplo: ‘cadena de caracteres’.

Variables
Es una de las formas en que el programa indicará a la computadora cuándo y cómo
almacenar información. Tal como la palabra lo dice, la información contenida en las
variables puede cambiar durante la ejecución del programa, según lo haya previsto el
programador.
No es obligatorio declarar variables, pero en casi todo programa su uso será necesario.
Una variable es una forma simplificada de hacer referencia a una posición de memoria.
Debido a que sería imposible conocer y recordar en qué dirección de memoria se encuentra
almacenado un dato, los lenguajes de programación nos permiten “enmascarar” esa
dirección con una palabra que podamos recordar. Por esto es que es recomendable colocar
nombres representativos a las variables (por ejemplo, para almacenar la edad de una
persona será más conveniente declarar una variable llamada “edad” que una llamada “a”, a
pesar de que ambos nombres serían válidos).
Las variables pueden ser globales o locales. Las globales tienen validez para todo el
programa, y suelen no ser utilizadas en la práctica. Las variables locales sólo existen en la
porción del programa en que son declaradas.
En Pascal una variable debe necesariamente ser declarada antes de ser utilizada, y debe
fijársele un tipo de dato. Al declarar una variable se reserva un espacio en la memoria,
según el tipo de dato que se haya definido. No es posible dar un valor inicial (“inicializar”)
a una variable al momento de su declaración.
La declaración se efectúa con la palabra reservada “var”, con el siguiente formato:
var nombre_de_variable : tipo_de_dato;

El identificador (nombre) de una variable puede ser cualquier sucesión de caracteres


alfanuméricos, y no puede comenzar con un número. El uso de mayúsculas y minúsculas es
indiferente, y el nombre elegido puede ser cualquier palabra elegida al azar, exceptuando
las palabras reservadas (palabras que son parte del lenguaje).
Se puede declarar más de una variable de un mismo tipo separando sus identificadores con
una coma, y variables de diferentes tipos separándolas con un punto y coma. Por ejemplo:
var nombre, apellido: string [50] ; letra: char ;

En este ejemplo se declararon dos variables de tipo “string” con un máximo de 50


caracteres (ocupan 50 bytes cada una), y una variable de tipo “char”.

Constantes
Las constantes permiten almacenar un valor estático en memoria, que no podrá cambiarse
durante la ejecución del programa. Son útiles para definir valores que podría ser necesario
cambiar en futuras versiones del programa. Por ejemplo, si para algún tipo de operación se
requiriera calcular el porcentaje de un impuesto, se puede colocar este número como
constante. Si, en el futuro, las leyes modifican el porcentaje aplicado, el valor puede
reemplazarse en la declaración de la constante y automáticamente cambiará dentro del
programa, en todas las porciones de código en que se utilice.
Para determinar su valor también es posible efectuar una operación aritmética o lógica, o
incluso usar funciones predefinidas del lenguaje.
Las constantes se declaran con la palabra reservada “const” seguida del identificador y el
valor a almacenar, sin indicar tipo. Las reglas para definir un identificador (nombre) de
constante son idénticas a las reglas para identificadores de variables. Ejemplo:
const impuesto_iva = 21;
numero = chr(73);
En este ejemplo se declararon dos constantes, una que almacena el número 21, y otra que
utiliza una función predefinida del lenguaje, “chr”, que permite convertir un número en el
caracter que le corresponde en la tabla ascii. En este caso, el número 73, que da como
resultado la letra “s”.

Asignación
La asignación de valores permite indicar qué información va a contener una variable. Sólo
se puede asignar valores a las variables, ya que las constantes son inmodificables.
Esta asignación tendrá lugar en tiempo de ejecución, es decir, el valor se almacenará
efectivamente en la memoria en el momento en que sea necesario, de acuerdo a la ejecución
del programa.
El operador de asignación es “:=” (dos puntos seguidos de un signo de igual).
Suponiendo que se ha declarado una variable llamada “nombre”, de tipo string, se le puede
asignar un valor de la siguiente forma:
nombre:= ‘Esteban’;

Otra forma de asignar un valor a una variable es mediante el resultado de alguna función
predefinida del lenguaje o una función creada por el programador. Por ejemplo:
longitud:= length(nombre);

En este caso se utilizó la función “length”, que recibe un dato de tipo string y devuelve un
valor de tipo integer con la cantidad de caracteres que tiene el string.
Por último, es posible asignar valores a las variables a través de ingresos por teclado. Esto
se hace utilizando la instrucción “read” seguido del nombre de la variable entre paréntesis.
Por ejemplo:
read(nombre);

Al ejecutar esta instrucción, el programa quedará a la espera de un ingreso por teclado de


valores de acuerdo al tipo de dato correspondiente a la variable. Si “nombre” es un string,
entonces podrá recibir una serie de caracteres. Si “nombre” fuera integer, deberá recibir un
número entero.

Tipos de datos definidos por el usuario


Muchas veces será necesario utilizar tipos de datos adaptados a las necesidades del
programa, definiendo valores que una variable de ese tipo puede adoptar. La palabra
reservada para esto es “type”, seguida del nombre que se le da al tipo de dato, el signo de
igual (“=”) y la construcción del tipo de dato. Una vez definido el tipo, se podrán declarar
variables que lo utilicen. Por ejemplo, si se construye un tipo de dato llamado “numeros”,
se podrá realizar una declaración como la siguiente: var edad: numeros.
Algunos ejemplos de tipos de datos definidos por el usuario son:
• Subintervalo: permite limitar el rango de valores que una variable puede adoptar. Sólo
puede establecerse un subrango de datos ordinales. Por ejemplo, si se necesitara una
variable que almacene dígitos entre el 0 y el 9, se podría definir un tipo de dato de la
siguiente forma:
type digito = 0 .. 9;

• Enumerado: en este caso el programador especifica uno a uno los valores que puede
adoptar el dato. Este tipo se convertirá en un tipo de dato ordinal, siendo el orden en que
sean definidos los valores lo que determinará su posición. El primer valor asignado recibirá
el número de orden 0, el siguiente el 1, luego el 2, etc. La sintaxis requiere que los valores
sean encerrados entre paréntesis y separados por coma. Por ejemplo:
type presidente = (Rivadavia, Urquiza, Derqui, Mitre, Sarmiento);

Una variable de tipo “presidente” puede adoptar uno de los cinco valores definidos,
correspondientes a los cinco primeros presidentes argentinos. En el ejemplo, Rivadavia
adopta la posición 0, Urquiza la posición 1, Derqui la 2, Mitre la 3 y Sarmiento la 4.
Existen otros tipos de datos que pueden ser definidos a comodidad del programador, como
conjuntos, vectores, registros, punteros, etc.

Ingreso e impresión de datos por pantalla


Frecuentemente será indispensable que el programa reciba datos que el usuario ingresa por
teclado, y también mostrar información en pantalla. Para esto se utilizarán las instrucciones
“read” para leer y “write” para escribir (visto desde el punto de vista de la computadora,
que será quien “lee” información que el usuario ingresa, o “escribe” en la pantalla lo que se
le indica).
Una variante para estas instrucciones es el agregado del sufijo “ln” (abreviatura de “line” –
línea-), que permite que el cursor sea colocado en la línea siguiente luego de ejecutar la
instrucción. De esta forma las instrucciones read y write se convierten en readln y
writeln.
• Write: recibe, entre paréntesis, un dato a imprimir por pantalla. Este dato puede estar
contenido en una variable, una constante, o ser ingresado como un valor constante dentro
de la misma instrucción. Por ejemplo:
write (nombre);

Suponiendo que la variable “nombre” es de tipo string y contiene la cadena de caracteres


‘Esteban’, la salida por pantalla durante la ejecución del programa mostrará Esteban.
De la misma forma, es posible colocar directamente una cadena de caracteres o un único
carácter a mostrar. Para que el compilador diferencie esto de nombres de variables, los
caracteres o cadenas de caracteres se colocan entre comillas simples:
writeln (‘Ingrese su nombre’);

También es posible efectuar combinaciones de ambas opciones, separando strings de


variables por medio de una coma. Por ejemplo, si existiera una variable de tipo real llamada
“saldo” que contiene una determinada cifra, puede imprimirse mediante la siguiente
instrucción:
write (‘El saldo de su cuenta es: ‘ , saldo);

Un detalle importante debe ser tenido en cuenta al momento de mostrar variables reales por
pantalla, ya que el programa probablemente mostrará una serie de decimales demasiado
grande, y aplicará exponentes para representarlos, por lo que, en el ejemplo anterior, podría
llegar a verse algo así: El saldo de su cuenta es: 4.5605500000E+03
Para evitar esto y “normalizar” el número, es posible indicarle cuántos dígitos se desean
visualizar de la parte entera del número, y cuántos decimales. Esto se hace colocando dos
puntos a continuación de la variable, la cantidad de dígitos enteros, otros dos puntos y la
cantidad de dígitos reales, de la siguiente forma:
write (‘El saldo de su cuenta es: ‘ , saldo:4:2);

Lo cual mostrará por pantalla algo como esto: El saldo de su cuenta es: 4560.55
• Read: guarda en una variable un valor ingresado por teclado, que debe coincidir con el
tipo de la variable (si, por ejemplo, la variable es de tipo integer y el usuario teclea letras,
ocurrirá un error en tiempo de ejecución). Se requiere que la variable haya sido declarada
previamente. El valor ingresado por teclado sobreescribirá cualquier dato previamente
guardado en la variable. Por ejemplo, si a la variable “nombre” que contenía el string
“Esteban” se le aplica la instrucción “read”, lo que el usuario ingrese por teclado pasará a
reemplazar el string “Esteban” por lo que haya recibido desde el teclado. La sintaxis es la
siguiente:
readln (nombre);

Inicialización de variables
Como ya se ha dicho, al declarar una variable se está reservando un espacio en la memoria
RAM para permitir el almacenamiento de información. Pero hasta tanto se le asigne
efectivamente un valor a esa variable, su contenido es incierto. Y en la memoria puede
haber datos previamente almacenados por otros programas que estuvieron ejecutándose,
por lo que no existen garantías de que una variable contenga un valor determinado, y es
probable que existan “restos” de otros programas ubicados justo en la posición de memoria
que se asignó a esta nueva variable. Es por este motivo que en algunos casos será necesario
darle un valor inicial (“inicializar”) a las variables.
Esto se hace con una simple asignación. Por ejemplo, si se hubiese declarado una variable
llamada “contador” de tipo integer:
contador:=0;

Pero, ¿cuándo es necesario inicializar? Es simple detectarlo: si en el primer uso que se hace
de la variable se le asigna un valor, entonces no será necesario inicializar, ya que lo primero
que se ha hecho con esa variable es justamente darle un valor que sustituya lo que contenía
anteriormente. Este sería el caso de una variable de tipo integer que se coloca dentro de un
readln. Lo que el usuario ingrese por teclado será almacenado en la memoria, sin importar
qué existía antes en ella, ya que el nuevo valor lo sobreescribe. Pero, si en el primer uso de
la variable se utiliza su valor inicial para operar con él (sumarle algo, restarle algo, etc.),
será necesario inicializar. Esto sucede al utilizar variables para llevar la cuenta de algo.
Si, por ejemplo, se declaró la variable “contador” como integer, y se planea utilizarla para
llevar la cuenta de cuántas veces sucede algo dentro del programa, esta instrucción tendrá
un aspecto similar al siguiente:
contador:=contador+1;

Pero si la variable “contador” tenía contenido “basura”, la primera vez que cuente que
sucedió lo que se esperaba, es posible que el resultado de “contador” sea 450, o 23345, o 6,
o cualquier cosa, en lugar del 1 que sería deseable. Así, antes de utilizar la instrucción que
emplea la variable, será neesario inicializarla en cero.
III. Estructuras de control
Las estructuras de control permiten dirigir el sentido que tomará la ejecución del programa.
Si una estructura contiene más de una sentencia, éstas deberán encerrarse entre las
instrucciones “begin” y “end;” para indicar que ese bloque de código corresponde a esa
estructura en particular.
Existen estructuras selectivas y estructuras repetitivas.

• Estructuras selectivas
Hacen que el curso del programa se bifurque en una u otra dirección dependiendo de las
condiciones que se cumplan durante su ejecución.

1. IF – THEN – ELSE: evalúa una proposición y efectúa una acción si el resultado es


verdadero, con el siguiente formato: si proposición=verdadera entonces ejecutar acción.
De manera opcional, se puede establecer una acción a realizar para el caso de que la
proposición evaluada resulte falsa: si proposición=verdadera entonces ejecutar acción 1.
Si no, ejecutar acción 2.
La sintaxis en pascal es la siguiente:
if proposición=verdadera then
ejecutar acción 1
else
ejecutar acción 2

La “acción 1” puede estar compuesta por más de una instrucción, en cuyo caso se colocará
una etiqueta “begin” al comienzo y “end;” al final, y cada sentencia dentro del bloque se
diferenciará de la siguiente mediante un punto y coma. Como excepción, si la estructura
lleva la instrucción else, en la línea inmediatamente anterior a ella debe obviarse el punto y
coma.
Pueden combinarse varias proposiciones unidas mediante conectores lógicos “and” - “or”.
En el caso del “and”, ambas condiciones deben resultar verdaderas para que se ejecute la
acción. En el caso del “or” basta con que una de ella resulte verdadera. Si se utilizan
proposiciones unidad por conectores lógicos, ellas deben estar encerradas entre paréntesis:
if (proposición_1 = verdadera) and (proposición_2 = verdadera) then
begin
sentencia 1
sentencia 2
end;
También puede expresarse la negación de una proposición anteponiendo la palabra
reservada “not”, que equivale a decir que el resultado de la evaluación debe ser falso:
if not proposición then
sentencia

2. CASE: se utiliza para seleccionar una opción de entre varias. Es una forma de evitar
múltiples “if”. La expresión a evaluar es llamada “selector” y consta de la palabra “ case”
seguida de una variable de tipo ordinal y la palabra reservada “of ”. Luego se establece una
lista de sentencias de acuerdo a diferentes valores que puede adoptar la variable.
Opcionalmente, se puede establecer un bloque “else” para el caso de que la variable adopte
un valor que no coincida con ninguna de las sentencias de la lista. Finalizada la estructura
del case se coloca un “end;” (en este caso no se corresponde con ningún “begin”). El
formato es el siguiente:
case variable_ordinal of
valor1: sentencia 1;
valor2: sentencia2;
valor3: sentencia3;
else
sentencia4;
end;

• Estructuras iterativas
Permiten que una sentencia o un bloque de código se repita una determinada cantidad de
veces.

1. FOR: realiza una iteración una cantidad de veces específica. Para ello necesita una
variable de tipo ordinal, a la que asignará valores dentro del rango que se le especifique,
incrementándose en uno. Por ejemplo, si se declara una variable llamada “cuenta” de tipo
integer, se puede utilizar un for con el siguiente formato:
for cuenta:= 5 to 9 do
sentencia
En este caso la sentencia se ejecutará cinco veces, ya que la variable “cuenta” primero
adoptará el valor 5, luego el valor 6, y así hasta llegar al 9, en que repetirá la sentencia por
última vez.
Por supuesto los valores pueden reemplazarse por variables o por constantes, siempre que
ellos hayan sido declarados y se les haya asignado algún valor previamente:
for cuenta:= 1 to maximo do
sentencia
Una variante es asignar los valores decrementando la variable. Es decir, para el primer
ejemplo, la variable adoptaría primero el valor 9, luego el 8, y así sucesivamente hasta
llegar al 5 y terminar la iteración. Esto se efectúa mediante la palabra reservada “downto”:
for cuenta:= 9 downto 5 do
sentencia

2. WHILE: Se evalúa una proposición (o un grupo de ellas unidas por conectores lógicos)
y, de resultar verdadera, se ejecuta la sentencia, repitiéndose el proceso hasta que la
proposición deje de ser verdadera. En este caso es importante prever que en algún momento
la proposición se vuelva falsa, porque de lo contrario se entraría en un bucle infinito. Por
ejemplo, si se utilizara un while para llevar la cuenta de algo, el formato sería similar al
siguiente:
contador:= 0;
read(edad);
while edad <= 21 do
begin
contador:= contador + 1;
read(edad);
end;
En este caso se utilizan dos variables de tipo entero, “contador” y “edad”, y el bloque de
código incrementa la variable “contador” en 1 cada vez que se lee de teclado una edad
menor o igual a 21.
Notar que se inicializó la variable “contador” en 0, para evitar que se sume contenido
“basura”, y que previamente a evaluar la proposición se le dio un valor a la variable “edad”
(asignado por teclado), ya que de lo contrario se estaría evaluando contenido “basura” en la
primera iteración. Luego, dentro del bloque, se vuelve a asignar un valor a la variable a
través del teclado, para que exista la posibilidad de que la proposición resulte falsa en algún
momento.
El while se caracteriza por evaluar la condición antes de ejecutar el bloque de código. Es
decir, si la proposición fuera falsa en la primera evaluación, el bloque nunca se ejecuta.

3. REPEAT: similar al while, funciona a la inversa de él: evalúa una proposición o una
serie de ellas y repite una sentencia o un bloque de código hasta que se cumpla una
condición. En este caso, primero se ejecutan las sentencias y luego se evalúa, y la iteración
se realizará mientras la proposición no sea verdadera. El formato es el siguiente:
contador:=0;
repeat
read (edad);
contador:= contador+1;
until edad > 21;
En este caso existe una excepción en cuanto a la regla de encerrar el bloque de código entre
etiquetas “begin” y “end”, aunque si se colocan no afectan la ejecución del programa.

IV. Modularización
Normalmente, un problema con cierta complejidad necesitará ser subdividido en partes para
facilitar su resolución.
Al abstraer un problema o situación de la realidad en un programa de computadora, esto
puede hacerse mediante la utilización de “módulos”, también llamados “subrutinas” o
“subprogramas”.
Ellos son útiles para dividir el programa en secciones más pequeñas que permiten resolver
cada situación en forma aislada, y para reutilizar código que puede ser necesario ejecutar
más de una vez.
Estos módulos deben comunicarse con alguna otra parte del programa (sea el programa
principal u otros módulos), de forma que todos estén unidos entre sí de una forma u otra.
Para comunicarse con los módulos se utilizan invocaciones y parámetros (argumentos).
En Pascal existen dos tipos de módulos: funciones y procedimientos.
Pascal provee funciones y procedimientos predefinidos para comodidad del programador.
Por ejemplo, no es necesario desarrollar una función que incremente el valor de una
variable de tipo ordinal, ya que existe la función predefinida “inc” que ejecuta esta acción.
Además de las funciones y procedimientos predefinidos, es posible agregar otros
provenientes de unidades externas, mediante la declaración “uses” y el nombre de la
unidad, al principio del código.
En cuanto a los parámetros, éstos son variables que se envían desde fuera del módulo y son
utilizados por éste. No es necesario que coincida el nombre de la variable enviada desde
fuera con el nombre del argumento que recibe el módulo, ya que éste sólo utilizará el valor
que la variable contiene, asignándole el nombre del argumento. La forma en que un módulo
reconoce a qué parámetro asignar cada valor es mediante el orden y tipo de las variables
enviadas. Por lo tanto, debe tenerse especial cuidado en pasar la misma cantidad de
variables que el módulo recibe, en el mismo orden y con coincidencia de tipos (se separan
por punto y coma en el módulo y por comas en la invocación):

Esta indiferencia respecto a los nombres es la que permite que un módulo sea invocado más
de una vez dentro de un mismo programa, enviándole variables con diferentes valores
(aunque siempre del mismo tipo).
También debe tenerse en cuenta que los módulos pueden tener variables locales, que sólo
tienen validez dentro del procedimiento y dejan de existir al finalizar la ejecución de éste.

• Funciones:
La palabra reservada que las identifica es “function”. Las funciones representan un valor, es
decir, una vez ejecutado el cuerpo de la función, ésta se sustituye en su invocación por el
resultado que arroja. Por ejemplo: si se crea una función cuya tarea es sumar dos números,
el resultado de esta suma reemplazará a la invocación hecha desde fuera de la función. Por
esto, las funciones siempre se asignan a una variable cuyo tipo coincida con el de la
función.
Su estructura está constituida por el nombre, la lista de argumentos que recibe y el tipo de
dato que retorna la función. El código que la compone se encierra entre etiquetas “begin” y
“end;” y antes de finalizar el cuerpo de la función se debe asignar el valor que ésta ha de
retornar.
En el ejemplo a continuación, se implementa una función que convierte una temperatura en
sistema Farenheit al sistema Celsius:
function convertir_a_celsius (farenheit: real): real;
var celsius: real;
begin
celsius:= (farenheit-32) / 1.8;
convertir_a_celsius:= celsius;
end;
Para invocar a esta función desde el programa principal o desde otro subprograma deberá
existir una variable de tipo real (ya que éste es el tipo de dato de la función) a la que se
asignará la función. Suponiendo que en el programa principal existen dos variables de tipo
real, llamadas “gradoscelsius” y “gradosfarenheit”, la llamada a la función anterior podría
realizarse de la siguiente forma:
gradoscelsius:= convertir_a_celsius(gradosfarenheit);

En este caso, la llamada a la función, convertir_a_celsius(gradosfarenheit), se


reemplazará por el valor de tipo real que la función arroje como resultado, y ese valor se
asignará a la variable “gradoscelsius”.

• Procedimientos:
Los procedimientos también pueden efectuar una acción en base a argumentos que reciben
desde fuera. Pero a diferencia de aquéllas, éstos pueden devolver uno o más resultados, o
incluso ninguno. Por ello su invocación se realiza en forma directa, sin asignar su valor a
ninguna variable, ya que los valores se retornarán dentro de los propios parámetros que se
envíen.
En este punto se hace necesario distinguir en qué casos un parámetro enviado a un
procedimiento retornará un valor diferente al que tenía cuando se lo envió, y cuándo no.
Esta diferencia se logra gracias a los parámetros/argumentos enviados por valor y por
referencia (también llamados “de entrada” y “de entrada/salida”).

1. Parámetros por valor: no son modificados durante la ejecución del módulo (de aquí el
nombre de “parámetros de entrada”, ya que “entran” al procedimiento pero no “salen”).
Esto se logra trabajando en base a una copia que se realiza en la memoria de la información
contenida en el parámetro. Suponiendo que en el programa principal se declaró una variable
de tipo integer, en la memoria se habrán reservado 2 bytes (que es el espacio que ocupa una
variable de este tipo) en los que se guardará determinada información. Si esta variable es
utilizada como parámetro para ser enviada por valor a un módulo, en la memoria se
ocuparán otros 2 bytes en los que se hará una copia de la información que la variable
contiene. El módulo entonces trabajará sobre esa copia, pudiendo modificarla o no, pero al
finalizar la ejecución del módulo esa copia desaparece (se libera el espacio en memoria) y
el valor original, en su posición de memoria original, queda intacto.
Se utilizan parámetros por valor cuando es necesario enviar al módulo información que
necesitará para trabajar, pero no es necesario que esa información forme parte del
resultado.

2. Parámetros por referencia: pueden ser modificados durante la ejecución del módulo.
Se identifican anteponiendo la palabra reservada “var” a su nombre (ya que son argumentos
“variables”, en el sentido de que pueden variar). En este caso, la información sólo existe
una vez en la memoria, y lo que se pasa al módulo en realidad es una referencia (la
dirección de memoria) que indica dónde está almacenada. Por esto se los llama “de
entrada/salida”, ya que la información se envía desde fuera al módulo pero también puede
“salir” de él. Como se podrá notar, esto es ficticio, ya que la información nunca “entra” ni
“sale”, sino que al enviarse la referencia a la posición de memoria que ocupa la
información, ésta es modificada directamente por el módulo, y al finalizar éste no hay
manera de recuperar el valor previo a esa modificación.

Volviendo a los procedimientos, la misma conversión de temperatura implementada


anteriormente con una función podría realizarse con un procedimiento de la siguiente
forma:
procedure convertir_a_celsius (farenheit: real; var celsius: real);
begin
celsius:= (farenheit-32) / 1.8;
end;
Y la llamada desde fuera del procedimiento:
convertir_a_celsius(gradosfarenheit, gradoscelsius);

En este caso el argumento “gradosfarenheit” se recibió por valor, ya que no es necesario


que sea modificado (es sólo información que se provee al procedimiento para que pueda
trabajar con ella). El argumento “gradoscelsius” se recibió por referencia ya que es
necesario que la información que contiene la variable sea modificada con el resultado de la
conversión.
Por supuesto, el primero de los parámetros debe contener algún valor antes de la invocación
al procedimiento (en este caso, una temperatura expresada en sistema farenheit), ya que de
otra forma no tendría sentido efectuar la conversión. No así el segundo parámetro, ya que
aunque su contenido fuera “basura” contenida en la memoria, su valor será reemplazado
por el resultado que arroje el procedimiento.

V. Otros tipos de datos compuestos definidos por el


usuario
Debido a que estos son datos que necesitan una especificación para poder ser utilizados, es
necesario definirlos al inicio del programa, con la palabra reservada “type”.

• Vectores:
Un vector es una agrupación de datos que tienen un orden (“arreglo”) y que son todos del
mismo tipo. Ese orden está dado por un índice, que dentro de Pascal es representado por
una variable de tipo ordinal, en un rango que se indica al declarar el tipo. La cantidad
máxima de elementos que un vector puede contener en Pascal es 250.
Los vectores se almacenan en la memoria en posiciones consecutivas, por lo que es posible
acceder en forma directa a alguno de los datos contenido en un vector por medio de su
índice.
La declaración de un vector se hace utilizando la palabra reservada “array”, seguida del
índice (límite inferior y límite superior) y el tipo de dato que el vector contendrá:
type vector = array [1 .. 50] of integer;

En este caso se ha declarado un tipo de arreglo que tiene 50 lugares para guardar números
enteros, con un índice que comienza en el número 1 y finaliza en el 50. Pero nada obsta a
que el índice comience en otro número arbitrario.
Al declarar una variable del tipo del arreglo que se ha definido se podrá acceder a un
elemento en particular del vector por medio de su índice. Por ejemplo, si en una variable de
tipo vector tal como fue descripto arriba se deseara asignar un valor al quinto elemento, se
podría hacer lo siguiente:
Declaración de la variable:
var arreglo: vector;

Acceso al quinto elemento del vector:


arreglo[5]:= 700;

Por supuesto, como el vector fue declarado de números enteros, sólo podrá asignársele un
valor entero. De la misma forma, debido a que se utilizaron números para determinar el
índice, se accederá colocando un número en los corchetes. Si el índice del vector fueran
caracteres que van de ‘a’ hasta ‘z’, el quinto elemento debería ser referenciado de la
siguiente forma:
arreglo['e']:= 700;

También puede referenciarse al índice por medio de una variable que coincida con el tipo
de dato utilizado para el índice. En caso de que el índice sea numérico (de tipo integer, ya
que el tipo real no es ordinal), podría utilizarse una variable de tipo integer como índice.
Esta es la forma en que generalmente se hará referencia a una posición del vector. Por
ejemplo, si se deseara rellenar el vector anterior con el número 0 en cada una de sus 50
posiciones, se podría declarar una variable de tipo entero (generalmente se declara una
variable llamada “i” aunque el nombre podría ser cualquier otro), y llenar el vector
utilizando una estructura iterativa:
for i:= 1 to 50 do
arreglo[ i ]:= 0;
Debe recordarse que no pueden asignarse tipos de datos diferentes entre sí. Por lo que, de
ser necesario rellenar un vector con la repetición de un número entero, no podría asignarse
este número directamente al vector (arreglo:=0), ya que el arreglo es de tipo array y el
número es de tipo integer. En cambio, el vector en cada una de sus posiciones sí contiene
datos de tipo integer, por lo que es perfectamente posible asignar como se hizo en el
ejemplo iterativo anterior.

• Matrices:
Una matriz no es más que un vector con dos dimensiones. En lenguaje coloquial se las
llama “tablas”, ya que son una combinación de filas y columnas. El tipo de datos que
contienen es homogéneo (es decir, todos datos del mismo tipo).
La declaración del tipo es muy similar a la de un vector, con la diferencia de que las
matrices poseen dos índices (el primero para las filas y el segundo para las columnas):
type matriz = array [1..5, 1..3] of integer;

Esta matriz de 5 filas y 3 columnas correspondería a un esquema gráfico como el siguiente:


Un elemento en una matriz se referencia con ambos índices: arreglo[4,1] corresponde a la
cuarta fila, primera columna.
Para recorrer una matriz, es necesario utilizar estructuras iterativas anidadas, ya que por un
lado se debe recorrer el índice de las filas y por otro el de las columnas:
for i:= 1 to 5 do
begin
for k:= 1 to 3 do
arreglo[i,j]:= 0;
end;

• Conjuntos:
Un conjunto es un grupo de elementos sin orden preestablecido (por lo que no existirá un
índice para referenciarlos). Podría simbolizarse como un recipiente que contiene elementos
mezclados al azar, pero que cumplen con algunas condiciones: los elementos no pueden
estar repetidos, deben ser todos del mismo tipo, el tipo debe ser ordinal, y existe un máximo
de 256 elementos.
La definición de un tipo conjunto se efectúa de la siguiente forma:
type conjunto = set of char;

Algunas operaciones que pueden realizarse con conjuntos son:


Asignación: para asignarle elementos a un conjunto, éstos se encierran entre corchetes. Si
fuera necesario asignar el vacío a un conjunto (es decir, eliminar cualquier elemento que
pudiera contener), la asignación sería de corchetes vacíos:
letras:= [ ];

Unión: se utiliza el signo + entre el conjunto y el elemento a agregar. Si el elemento ya


perteneciera al conjunto, éste no sufrirá modificaciones:
letras:= letras + ‘g’;

Diferencia: se utiliza el signo – entre dos conjuntos, lo que resultará en un nuevo conjunto
conteniendo los elementos que pertenecen al primer conjunto y no pertenecen al segundo:
conj3:= conj1 – conj2;

Comparación: se pueden comparar dos conjuntos con el signo de igual (“=”) o con el de
desigualdad (“<>”). El resultado de esta operación devolverá un valor boolean:
conj1 = conj2 (será “true” o “false” dependiendo del contenido de ambos)
Inclusión: es posible saber si un elemento se encuentra incluido en un conjunto mediante la
palabra reservada in. Esto arrojará un valor boolean dependiendo de si el elemento
pertenece o no al conjunto. Suele utilizarse en expresiones condicionales, como la que
sigue:
if ‘a’ in letras then

• Registros:
Un registro es una estructura que permite agrupar datos de diversos tipos con algún tipo de
correspondencia lógica. Cada uno de estos datos que componen un registro es llamado
“campo”.
Un campo tiene un nombre y un tipo, ya que cada uno de ellos es una variable (sólo que en
este caso la palabra “var” no aparece).
Un ejemplo de utilización sería el de un registro conteniendo los datos de una persona, en la
que los campos podrían ser el nombre y apellido (de tipo string), la edad (de tipo integer),
el sueldo (de tipo real), etc.
Una estructura de estas características se define de la siguiente forma:
type empleados = record
nombre: string[50];
edad: integer;
sueldo: real;
end;
Nótese que la estructura finaliza con la etiqueta “end;”, pero no existe un “begin” que le
corresponda.
Los datos contenidos en un campo pueden ser de cualquier tipo, incluso otros datos
estructurados (por ejemplo, uno de los campos podría estar constituido por un arreglo).
Definido el tipo, se puede declarar una variable del tipo registro y asignarle valores a cada
uno de los campos. Para referenciar a cada uno de ellos se utiliza un punto separando el
nombre de la variable del nombre del campo. Siguiendo el ejemplo anterior, podría
definirse una variable llamada “roberto” del tipo “empleados”, y completar cada uno de sus
campos de la siguiente forma:
roberto.nombre:= ‘Roberto Gomez’;
roberto.edad:= 58;
roberto.sueldo:= 2440.5;
Un registro puede ser asignado a otro sin necesidad de hacer referencia a cada uno de sus
campos, siempre que ambos sean del mismo tipo. Por ejemplo, si se tuviera una variable
llamada “andres” de tipo “empleados” y se deseara rellenar sus campos con los mismos
datos que contiene el registro “roberto”, podría hacerse la siguiente asignación: andres:=
roberto;
Podrá observarse que el uso de muchas variables de tipo registro pueden resultar engorrosas
en caso de necesitar gran cantidad de ellas. Supóngase que una empresa debe mantener
información de sus 100 empleados. Sería casi imposible mantener el código para almacenar
los datos de cada uno de ellos en variables separadas. Por esto es que los registros suelen
agruparse en otras estructuras, como los vectores.

• Vectores de registros:
Se trata de la construcción de un arreglo, tal como se haría con cualquier otro, cuyo tipo de
dato sea un tipo registro. Para esto se hará necesario que el tipo registro esté definido con
anterioridad. Por ejemplo:
type empleados = record
nombre: string[50];
edad: integer;
sueldo: real;
end;
vector = array [1 .. 100] of empleados;
De esta forma, pueden organizarse varios registros dentro de un arreglo ordenado de ellos.
Si pudiera visualizarse al vector resultante de esta definición, se podría graficar de la
siguiente manera:

En este caso, el nombre de la variable de tipo record será el de la variable de tipo array con
su índice, seguido del punto y el nombre del campo: suponiendo que se declaró una
variable llamada “arreglo”, y el índice se referencia con una variable entera “i”, se puede
acceder a cada campo de cada posición del arreglo de la siguiente forma:
arreglo[ i ].nombre
arreglo[ i ].edad
arreglo[ i ].sueldo
De esta forma se podría llenar cada campo de los registros contenidos en un vector
utilizando una estructura iterativa, como en el ejemplo siguiente:
i:= 1;
write(‘Ingrese nombre del empleado. Para terminar ingrese zzz: ‘);
readln(n);
while (i <= 100) and (n <> ‘zzz’) do
begin
arreglo[ i ].nombre:= n;
write(‘Ingrese edad del empleado: ‘);
readln(arreglo[ i ].edad);
write(‘Ingrese sueldo del empleado: ‘);
readln(arreglo[ i ].sueldo);
write(‘Ingrese nombre del empleado. Para terminar ingrese zzz: ‘);
readln(n);
i:= i+1;
end;
Deben realizarse algunas observaciones en cuanto a este ejemplo. En primer lugar, debido a
que la estructura utilizada es un while, el índice del arreglo debe moverse “manualmente”.
Por esto se utiliza una variable “i” del mismo tipo que el índice (en este caso, integer), que
se inicializa en 1 (ya que el primer elemento del arreglo tiene el índice 1) y se la incrementa
dentro de cada iteración.
La razón para utilizar una estructura while es que ésta permite establecer una condición de
corte para el caso de que se desee interrumpir la carga de datos antes de completar todos los
espacios disponibles en el vector. En el ejemplo la condición de corte es que el nombre
ingresado sea “zzz”.
Así, la condición a evaluar en el while es doble: por un lado, que el índice (i) no supere el
máximo de espacio del vector (en este ejemplo, cien); por otro, que el nombre sea diferente
de “zzz”.
Para permitir evaluar la condición de corte, es necesario que la variable contenga algún
valor para que sea evaluado en la primera iteración. En este caso, como los datos deben ser
almacenados en el vector siempre y cuando el nombre no sea “zzz”, se utiliza una variable
auxiliar del mismo tipo que el campo “nombre” (string), ya que si se leyera directamente
sobre la variable a almacenar en el vector (arreglo[ i ].nombre), el nombre “zzz” quedaría
cargado.

VI. Algunas funciones y procedimientos para trabajar


con strings
Estas son algunas de las muchas funciones y procedimientos predefinidos de Pascal que
permiten manipular variables de tipo string.
Debe tenerse en cuenta que un string puede recorrerse con un índice numérico, de la misma
forma que un vector, comenzando por el número 1:

• LENGTH:
Recibe como argumento un string y devuelve un valor de tipo integer con la longitud del
string.
Ejemplo:
longitud:= length(cadena);
donde longitud es un integer y cadena un string;

• POS:
Recibe como argumento un sub-string y un string, y devuelve un integer representando la
posición de inicio del primero dentro del segundo. Si no se encuentra, devuelve cero.
Debido a que un caracter puede ser parte de un string, es posible pasarle como parámetro
un único caracter, en cuyo caso retornará la posición en que éste se encuentra dentro del
string. Si se encuentra más de una vez, sólo retorna la posición de la primera ocurrencia.
Ejemplos:
posicion:= pos(‘o’, cadena);
posicion:= pos(‘hola’, cadena);
donde posicion es un integer y cadena un string

• COPY:
Recibe como argumentos un string y dos enteros y devuelve un valor de tipo string. Permite
extraer parte del string que se pasa como parámetro, comenzando en la posición que se le
pasa como segundo parámetro, y extrayendo tantos caracteres como el tercer parámetro
indique.
Ejemplo:
subcadena:= copy(cadena, 6, 10);
donde cadena y subcadena son strings. Si la variable cadena contiene ‘hola mundo’, esta
función retornará la subcadena ‘mundo’.
Lápiz elefante carro alfajor

You might also like