Programación en Pascal/Tipos avanzados
Es bastante usual que se necesite agrupar datos distintos. Imagina por ejemplo que necesitamos llevar las fichas de una biblioteca; necesitamos almacenar, en cada ficha, el nombre y la dirección del miembro, los libros que se ha llevado, si los ha devuelto, etc. Esto puede ser un caos si cada cosa se almacena en variables distintas. Por eso se crearon los Records.
Tabla de contenidos
Tipos en Pascal
Clasificación de tipos Tipos estructurados
Tipo Registro
Motivación Definición de un registro Ejemplo(1) Ejemplo(2) Ejemplo(3) Acceso a campos de registros Lectura de un registro Escritura de un registro Ejemplo El tipo Fecha Comparación de Fechas La instrucción with Ambigüedad con with Asignación de registros Estructuras complejas
Registros variantes
Motivación Ejemplo Ejemplo (cont) Ejemplo. Figuras Creando una figura Área de una figura Comparación de posición
Array con tope
Definición Cómo funciona Crear conjunto vacío Insertar un elemento Eliminar un elemento Búsqueda de un elemento
Tipos en Pascal Clasificación de tipos
Elementales
Ordinales o escalares: Integer, Char, Boolean, subrangos, enumerados.
Otros: real
Estructurados:
arreglos (array)
conjuntos (set)
registros (record)
Tipos estructurados
Arreglos: Secuencias homogéneas de tamaño fijo. El orden es relevante y puede haber repetidos.
Conjuntos: Conjuntos en el sentido matemático, sin orden, no hay repetidos. El tamaño es variable pero acotado.
Registros: Colección heterogénea y ordenada de datos. Conocidos como tuplas. Tamaño fijo.
Tipo Registro Motivación
Es usual la representación de objetos o entidades de la realidad mediante estructuras de datos.
Una de las estrucutras más utilizadas con este fin es el record.
Un record es una tupla de datos de diferente tipo, cada uno de los cuales se accede mediante un nombre de campo.
Por ejemplo,
CI Nombre Direc. Tel.
+---------+---------------+---------+---------+
estudiante | 4235678 | Juan Gonzalez | Yi 2345 | 6718990 |
+---------+---------------+---------+---------+
Definición de un registro
type
T = record
campo1 : tipo1;
campo2 : tipo2;
...
campok : tipok
end;
Donde campo-i es un identificador que da nombre a un campo y tipo-i es su correspondiente tipo. Ejemplo(1)
Datos de un estudiante.
type TCedula = array [1..8] of 0..9; TNombre = array [1..45] of char; TTelefono = array [1..7] of 0..9; TDirec = array [1..40] of char;
TEstudiante = record
cedula : TCedula;
nombre : TNombre;
telefono : TTelefono;
direccion : TDirec
end;
Ejemplo(2)
Los puntos del plano pueden representarse como una pareja de reales:
type
punto = record
coordenadaX,
coordenadaY : real
end;
Ejemplo(3)
Los números racionales pueden representarse así:
type
TSigno = (mas,menos);
natural = 0..MaxInt;
positivo = 1..MaxInt;
racional = record
signo : TSigno;
numerador : natural;
denominador : positivo;
end;
Acceso a campos de registros
El operador . (punto) seguido del nombre del campo se utiliza para acceder a los componentes de un registro.
var q : racional
...
q.signo:= mas;
q.numerador:= 4;
WriteLn(q.denominador);
...
Lectura de un registro
No es posible aplicarle read a una variable de un tipo registro.
procedure LeerRacional(var q : racional);
var
signo : -1..+1;
begin
Write('Ingrese signo(-1,0,+1): ');
ReadLn(signo);
if signo = -1 then
q.signo:= menos
else
q.signo:= mas;
Write('Ingrese denominador: ');
ReadLn(q.denominador);
Write('Ingrese numerador: ');
ReadLn(q.numerador);
end; {LeerRacional}
Escritura de un registro
Para mostrar un registro se debe desplegar campo por campo.
procedure MostrarRacional(q :racional);
begin
if q.signo = menos
then Write('-'); (* signo *)
Write(q.numerador); (* numerador *)
Write('/'); (* separador *)
Write(q.denominador); (* denominador *)
end; {MostrarRacional}
Ejemplo
La suma de dos racionales.
function SignoRac(q: racional): integer;
begin
case q.signo of
mas : SignoRac:= +1;
menos : SignoRac:= -1;
end
end; {SignoRac}
procedure SumaRacionales(p,q: racional; var resultado: racional); var num: integer; begin
resultado.denominador:= q.denominador * p.denominador;
num:= SignoRac(p) * p.numerador * q.denominador
+
SignoRac(q) * q.numerador * p.denominador;
resultado.numerador:= abs(num);
if num < 0 then
resultado.signo:= menos
else
resultado.signo:= mas
end; {SumaRacionales}
El tipo Fecha
No existe un tipo fecha predefinido en Pascal.
type
TFecha = record
anio: 0..10000;
mes : 0..12;
dia : 1..31;
end;
Comparación de Fechas
function AnteriorFecha(f1,f2: TFecha) : boolean;
begin
if f1.anio = f2.anio then
if f1.mes = f2.mes then
AnteriorFecha:= f1.dia < f2.dia
else
AnteriorFecha:= f1.mes < f2.mes
else
AnteriorFecha:= f1.anio < f2.anio;
end; {AnteriorFecha}
La instrucción with
La instrucción with permite simplificar la forma de referenciar los campos de un registro.
procedure MostrarRacional(q :racional);
begin
with q do
begin
if signo = menos
then Write('-'); (* signo *)
Write(numerador); (* numerador *)
Write('/'); (* separador *)
Write(denominador); (* denominador *)
end; {with}
end; {MostrarRacional}
Ambigüedad con with
var q : racional; signo: integer;
...
with q do
begin
...
signo:= 1; (* error! representa q.signo *)
...
signo:= mas; (* correcto *)
...
end;
Asignación de registros
Una variable de tipo registro se puede asignar a otra del mismo tipo.
var p1,p2: punto; ... p1 := p2; (* asignación campo a campo *) ...
Estructuras complejas
Anidamiento de tipos estructurados.
type TFechas = array [1..Max] of fecha; ... begin
a[7].anio := 1968; (* campo anio de la séptima celda *) ...
Registros variantes Motivación
Se quiere representar una entidad que puede pertenecer a diferentes categorías.
Según la categoría hay diferentes datos.
Existe un conjunto de datos comunes a todas las categorías (eventualmente vacío). Ejemplo
Categorías:
Estudiante:
Año de Ingreso
Cantidad de materias
Docente
Carga horaria
Grado
Egresado
Año de egreso
Título
Datos comunes a todas las categorías:
Cédula.
Credencial cívica.
Ejemplo (cont)
type
TOrden = (docente,estudiante,egresado);
...
TUniveritario = record
cedula : TCedula;
credencial : TCredencial;
case orden:TOrden of
docente : (
grado: 1..5;
carga: 0..40
);
estudiante : (
semestre: 1..15;
materias: integer
);
egresado : (
egreso: 1900..3000;
titulo: TTitulo
);
end;
Ejemplo. Figuras
const
MaxFig = 30;
type
RGBColor = record
red,
green,
blue : 0..255;
end;
TipoFigura = (circulo,cuadrado,rectangulo);
punto = record
x,y: real;
end;
figura = record
color: RGBColor;
case clase: TipoFigura of
circulo : (
radio: real;
centro: punto
);
cuadrado: (
lado: real;
verticeSupIzq: punto
);
rectangulo: (
base,altura: real;
verticeInfIzq: punto
);
end;
Creando una figura
Para crear una figura se deben asignar los campos correspondientes de acuerdo a la categoría.
(* creación de un rectángulo *)
r.color.red:= 10; r.color.green:= 121; r.color.blue:= 203; r.clase:= rectangulo; r.base:= 12.4; r.altura:= 345.90; r.verticeInfIzq.x:= 0.9; r.verticeInfIzq.y:= 19.78;
Área de una figura
El campo discriminante es el que permite identificar cada categoría.
function areaFigura(fig : Figura): real;
begin
with fig do begin
case fig.clase of
circulo : areaFigura := PI * sqr(radio);
rectangulo : areaFigura:= base * altura;
cuadrado : areaFigura:= sqr(lado);
end; { case }
end; { with }
end; {areaFigura}
Comparación de posición
function masArriba(fig: figura; alt: real): boolean;
begin
with fig do begin
case clase of
circulo : masArriba:= (centro.y - radio) > alt;
rectangulo : masArriba:= verticeInfIzq.y > alt;
cuadrado : masArriba:= (verticeSupIzq.y - lado) > alt;
end; { case }
end; {with}
end; {masArriba}
Array con tope Definición
Otra posible representación de conjuntos es la siguiente:
Type
Conjunto = record
elems : array [1..N] of T0;
tope : 0..N
end;
donde ahora T0 no necesita ser un tipo escalar. Solo se requiere que los valores de tipo T0 sean comparables por igualdad. Cómo funciona
El array elems almacena los elementos del conjunto.
Los elementos se almacenan en las celdas 1 a tope
El campo tope apunta a la última posición ocupada del array.
El conjunto vacío se representa mediante el campo tope en 0.
Pueden representarse conjuntos que contengan de 0 a N elementos
Crear conjunto vacío
type
Conj = record
elems : array [1..N] of T;
tope : 0..N
end;
Procedure CrearConjuntoVacio(var S : Conj); begin S.tope := 0 end;
Insertar un elemento
procedure Insertar(e : T; var S : Conj);
{ pre condicion: (e no pertenece a S) y (S.tope < N)}
begin
with S do
begin
tope := tope + 1;
elems[tope] := e
end;
end;
Eliminar un elemento
Si el elemento no está no hace nada.
procedure Eliminar(e : T; var S : Conj);
var i : integer;
begin
i := 1;
{ evaluacion por circuito corto }
while (i <= S.tope) and (S.elems[i] <> e) do
i : = i + 1;
if i <= S.tope then
begin
S.elems[i] := S.elems[tope];
S.tope := S.tope - 1
end
end;
Búsqueda de un elemento
function pertenece(e : T; S : Conj) : boolean;
var
i: integer;
begin
i:= 1;
{ evaluacion por circuito corto }
while (i <= S.tope) and (S.elemns[i] <> e) do
i:= i+1;
pertenece:= i<=S.tope;
end;