4.3. Registros (records)
4.3.1. ¿Qué es un registro?
La principal limitación de un array es que todos los datos que contiene deben ser del mismo tipo. Pero a veces nos interesa agrupar datos de distinta naturaleza, como pueden ser el nombre y la edad de una persona, que serían del tipo string y byte, respectivamente. En ese caso, podemos emplear los records o registros, que se definen indicando el nombre y el tipo de cada dato individual (cada campo), y se accede a estos campos indicando el nombre de la variable y el nombre del campo, separados por un punto:
(* RECORD1.PAS, Contacto con los "record" *) (* Parte de CUPAS5, por Nacho Cabanes *) program Record1; var dato: record nombre: string[30]; edad: byte; end; begin dato.nombre := 'Ignacio'; dato.edad := 23; write('El nombre es ', dato.nombre ); write(' y la edad ', dato.edad); end. (* Resultado: El nombre es Ignacio y la edad 23 *)
La peculiaridad en la definición de un "record" es la aparición de una palabra end después de los nombres de los campos, lo que indica que hemos terminado de enumerar éstos.
4.3.2. Abreviando con "with"
Puede parecer engorroso el hecho de escribir "dato." antes de cada campo. También hay una forma de solucionarlo: cuando vamos a realizar varias operaciones sobre los campos de un mismo registro (record), empleamos la orden with, con la que el programa anterior quedaría
(* RECORD2.PAS, "record" y "with" *) (* Parte de CUPAS5, por Nacho Cabanes *) program Record2; var dato: record nombre: string[30]; edad: byte; end; begin with dato do begin nombre := 'Ignacio'; edad := 23; write('El nombre es ', nombre ); write(' y la edad ', edad); end; end. (* Resultado: El nombre es Ignacio y la edad 23 *)
En este caso tenemos un nuevo bloque en el cuerpo del programa, delimitado por el "begin" y el "end" situados más a la derecha, y equivale a decir "en toda esta parte del programa me estoy refiriendo a la variable dato". Así, podemos nombrar los campos que queremos modificar o escribir, sin necesidad de repetir a qué variable pertenecen.
Nota: aquí vuelve a aparecer la escritura indentada: para conseguir una mayor legibilidad, escribimos un poco más a la derecha todo lo que depende de la orden "with". No es algo obligatorio, pero sí recomendable.
4.3.3. Arrays de registros
Es habitual no usar un único registro, sino un conjunto de ellos, de modo que tendríamos un array de registros. Por ejemplo, podríamos guardar los datos de 5 personas con una estructura como ésta:
(* ARR_REC.PAS, "array" de varios "record" *) (* Parte de CUPAS5, por Nacho Cabanes *) program RecordArray; var datos: array [1..10] of record nombre: string[30]; edad: byte; end; begin datos[1].nombre := 'Ignacio'; datos[1].edad := 23; write('El primer nombre es ', datos[1].nombre ); write(' y la primera edad ', datos[1].edad); end. (* Resultado: El primer nombre es Ignacio y la primera edad 23 *)
Podemos usar un array de registros para crear una pequeña agenda, que nos permita guardar datos de personas y ver los datos almacenados, empleando un menú básico:
(* AGENDA0.PAS, Ejemplo de "Agenda": *) (* Permite añadir datos y mostrarlos *) (* Parte de CUPAS5, por Nacho Cabanes *) program Agenda0; var gente: array [1..1000] of { Los datos } record nombre: string; email: string; anyoNacimiento: integer; end; cantidad: integer; { Cantidad de datos existentes } opcion: integer; { Opción escogida } i: integer; { Para bucles "for" } {Cuerpo del programa principal} begin cantidad := 0; repeat WriteLn('Agenda'); WriteLn; WriteLn('1- Añadir una nueva persona'); WriteLn('2- Ver nombres de todos'); WriteLn('0- Salir'); Write('Escoja una opción: '); ReadLn(opcion); WriteLn; case opcion of 1: { Añadir datos de una persona } if cantidad < 1000 then begin cantidad := cantidad + 1; WriteLn('Introduciendo la persona ', cantidad); Write('Introduzca el nombre: '); ReadLn(gente[cantidad].nombre); Write('Introduzca el correo electrónico: '); ReadLn(gente[cantidad].email); Write('Introduzca el año de nacimiento: '); ReadLn(gente[cantidad].anyoNacimiento); WriteLn; end else WriteLn('Base de datos llena'); 2: { Ver nombres de todos } begin if cantidad = 0 then WriteLn('No hay datos') else for i := 1 to cantidad do WriteLn(i, ' ', gente[i].nombre); WriteLn; end; 0: { Salir de la aplicación } begin WriteLn; WriteLn('Saliendo...'); WriteLn; end; else begin WriteLn; WriteLn('Opción incorrecta!'); WriteLn; end; end; { Fin de "case" } until opcion = 0; end.
Este esqueleto es fácil de ampliar. Por ejemplo, podemos añadir la opción de buscar cualquier ficha que contenga un cierto texto, usando "pos" para ver si aparece en cualquier posición y un "boolean" para llevar la cuenta de si hemos encontrado alguna ficha correcta o no:
(* AGENDA0B.PAS, Ejemplo de "Agenda" *) (* Permite añadir datos, mostrarlos y buscar *) (* Parte de CUPAS5, por Nacho Cabanes *) program Agenda0b; var gente: array [1..1000] of { Los datos } record nombre: string; email: string; anyoNacimiento: integer; end; cantidad: integer; { Cantidad de datos existentes } opcion: integer; { Opción escogida } i: integer; { Para bucles "for" } textoBuscar: string; { Para búsquedas } encontrado: boolean; { Idem } {Cuerpo del programa principal} begin cantidad := 0; repeat WriteLn('Agenda'); WriteLn; WriteLn('1- Añadir una nueva persona'); WriteLn('2- Ver nombres de todos'); WriteLn('3- Buscar una persona'); WriteLn('0- Salir'); Write('Escoja una opción: '); ReadLn(opcion); WriteLn; case opcion of 1: { Añadir datos de una persona } if cantidad < 1000 then begin cantidad := cantidad + 1; WriteLn('Introduciendo la persona ', cantidad); Write('Introduzca el nombre: '); ReadLn(gente[cantidad].nombre); Write('Introduzca el correo electrónico: '); ReadLn(gente[cantidad].email); Write('Introduzca el año de nacimiento: '); ReadLn(gente[cantidad].anyoNacimiento); WriteLn; end else WriteLn('Base de datos llena'); 2: { Ver nombres de todos } begin if cantidad = 0 then WriteLn('No hay datos') else for i := 1 to cantidad do WriteLn(i, ' ', gente[i].nombre); WriteLn; end; 3: { Buscar una persona } begin Write('¿Qué texto busca? '); ReadLn( textoBuscar ); encontrado := false; for i := 1 to cantidad do if pos (textoBuscar, gente[i].nombre) > 0 then begin encontrado := true; WriteLn( i,' - Nombre: ', gente[i].nombre, ', Email: ', gente[i].email, ', Nacido en: ', gente[i].anyoNacimiento); end; if not encontrado then WriteLn('No se ha encontrado.'); WriteLn; end; 0: { Salir de la aplicación } begin WriteLn; WriteLn('Saliendo...'); WriteLn; end; else begin WriteLn; WriteLn('Opción incorrecta!'); WriteLn; end; end; { Fin de "case" } until opcion = 0; end.
4.3.4. Registros variantes
Hasta ahora hemos visto los registros (records), utilizando campos fijos, pero no tiene por qué ser necesariamente así. Tenemos a nuestra disposición los registros variantes, en los que con un "case" podemos elegir unos campos u otros. La mejor forma de entenderlos es con un ejemplo.
(* REGVAR.PAS, registros variantes *) (* Parte de CUPAS5, por Nacho Cabanes *) program RegistrosVariantes; var punto: record case cartesiano: boolean of true : (X,Y,Z : real); false : (R,theta,phi : real); end; begin punto.cartesiano := true; punto.x := 5; punto.y := -1; punto.z := 2.3; writeLn('Con coordenadas cartesianas, x vale ',punto.x:2:1); punto.cartesiano := false; punto.r := 12.3; punto.theta := -15; punto.phi := 45; writeLn('Con coordenadas esfericas, phi vale ',punto.phi:2:1); end. (* Resultado: Con coordenadas cartesianas, x vale 5.0 Con coordenadas esfericas, phi vale 45.0 *)
Realmente, no es necesario usar un campo para cambiar entre un juego de valores y otro, porque realmente se trata de varios conjuntos de capas que "se solapan", ocupando el mismo espacio en memoria:
(* REGVAR2.PAS, registros variantes (2) *) (* Parte de CUPAS5, por Nacho Cabanes *) program RegistrosVariantes2; var punto: record case boolean of true : (X,Y,Z : real); false : (R,theta,phi : real); end; begin punto.x := 5; punto.y := -1; punto.z := 2.3; writeLn('Con coordenadas cartesianas, x vale ',punto.x:2:1); punto.r := 12.3; punto.theta := -15; punto.phi := 45; writeLn('Con coordenadas esfe ricas, phi vale ',punto.phi:2:1); writeLn('Como curiosidad, x vale ',punto.x:2:1); end. (* Resultado: Con coordenadas cartesianas, x vale 5.0 Con coordenadas esfericas, phi vale 45.0 Como curiosidad, x vale 12.3 *)
El riesgo, como se ve en este último ejemplo, es que al modificar un juego de valores, el otro se altera a la vez, ya que están solapados en memoria, pero los datos posiblemente no tendrán sentido si accedemos a ellos usando campos distintos de los que habíamos empleado para guardar la información.
No hay comentarios:
Publicar un comentario