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;