Está en la página 1de 7

6

ESTRUCTURAS DE DATOS (II): REGISTROS Y ARCHIVOS DE DATOS


En el Captulo 4 conocimos el concepto de array, una de las estructuras de datos estticas ms habituales. En la primera parte de este captulo trataremos otra estructura de datos esttica, los registros, que nos permitirn representar colecciones formadas por datos de distintos tipos. La segunda parte la dedicaremos al manejo de archivos de datos, concepto habitualmente relacionado con el uso de registros.

6.1 REGISTROS
Los arrays nos permiten agrupar datos con la condicin de que sean todos de un mismo tipo. Existe un tipo de datos compuesto denominado registro que se puede utilizar para agrupar informacin relacionada entre s pero formada por datos de tipos distintos. Un tipo registro est definido por un conjunto de componentes, denominados campos, que establecen su estructura. Cada dato de tipo registro podr tener ciertos valores asignados a sus campos. Para trabajar con registros, es necesario en primer lugar definir la estructura de campos del tipo registro. Para ello, definiremos un nuevo tipo con el que posteriormente podremos declarar variables de dicho tipo. En la fase de diseo, la definicin de tipos se situar en una seccin especfica de la parte declarativa, que titularemos TIPOS e ir situada inmediatamente despus de la seccin CONSTANTES. En concreto, la definicin de un tipo registro utilizar el siguiente diagrama sintctico: identificador de tipo registro = identificador de campo , : tipo

73

6. ESTRUCTURAS

DE

DATOS (II): REGISTROS Y ARCHIVOS

DE

DATOS

En lenguaje C, el tipo registro se representa con el tipo estructura, cuya definicin se sita inmediatamente despus de la definicin de constantes y obedece al siguiente diagrama sintctico: typedef struct { tipo identificador de campo , ; }

identificador de tipo registro Por ejemplo, para representar la siguiente informacin de un alumno:
alumno id 5 nombre Antonio Gonzlez grupo B nota 6.125

puede definirse un tipo registro de la siguiente forma: En algoritmia:


TIPOS tipoAlumno = id:entero nombre[35]:carcter grupo:carcter nota:real

En C:
typedef struct { int id; char nombre[35]; char grupo; double nota; } tipoAlumno;

Para utilizar un tipo registro, ser necesario declarar variables de dicho tipo: En algoritmia:
VARIABLES alumno: tipoAlumno

En C:
tipoAlumno alumno;

Ahora bien, un registro contiene varios campos de informacin, por lo que para acceder a ellos de forma independiente ser necesario especificar el campo que nos interesa. En concreto, deber indicarse el identificador de la variable registro que lo contiene seguido de un punto (operador denominado descriptor de campo) y del identificador de campo (por ejemplo, alumno.id, alumno.nombre, alumno.grupo o alumno.nota). Un campo as especificado puede tratarse como si fuera una variable del mismo tipo que el campo y, por tanto, se le podrn aplicar las operaciones permitidas sobre variables de ese mismo tipo (por ejemplo, podrn realizarse operaciones aritmticas sobre alumno.nota). En C, el descriptor de campo es un operador con mayor prioridad que ningn otro (incluidos todos los operadores unarios estudiados hasta el momento). Por lo tanto, cuando se pase un parmetro de tipo registro por referencia a un mdulo, dado que el parmetro formal ser un puntero a un registro, el acceso a uno de sus campos requerir que el operador de indireccin y el identificador del parmetro formal aparezcan encerrados entre parntesis. Por ejemplo, si pAlumno es un puntero a un registro de tipo tipoAlumno, para referirnos al campo grupo deberemos utilizar la sintaxis (*pAlumno).grupo. Para simplificar la sintaxis, existe en C una forma abreviada de indicar esto mismo utilizando el operador ->. As pAlumno->grupo equivale a (*pAlumno).grupo. 74

6. ESTRUCTURAS

DE

DATOS (II): REGISTROS Y ARCHIVOS

DE

DATOS

A diferencia de lo que ocurre con arrays, en C todos los valores de una variable registro pueden asignarse a otra variable registro en una sola instruccin mediante el operador de asignacin:
tipoAlumno alumno1,alumno2; (...) alumno2=alumno1;

Tambin, a diferencia de los arrays, en C un registro puede pasarse por valor as como devolverse asociado al nombre de la funcin. Por ejemplo, los siguientes prototipos de funciones son vlidos:
tipoAlumno leerAlumno(); void mostrarAlumno(tipoAlumno alumno);

Por otro lado, al igual que en el tipo registro tipoAlumno uno de los campos era de tipo cadena, es posible que otros campos sean de cualquier otro tipo de datos compuesto. Por ejemplo, podran representarse en el registro las calificaciones del alumno en 10 asignaturas distintas
alumno id nombre grupo notas 0123456789

utilizando un campo de tipo vector para las calificaciones, del siguiente modo:
typedef struct { int id; char nombre[35]; char grupo; double notas[10]; } tipoAlumno; (...) tipoAlumno alumno;

Para referirnos a la calificacin del alumno en la tercera asignatura utilizaremos la sintaxis alumno.notas[2]. Del mismo modo, a menudo es necesario representar en un programa, no un dato de tipo registro, sino una coleccin de datos de tipo registro. Esto se puede implementar utilizando arrays cuyos elementos son registros. Por ejemplo, lo ms probable es que un programa requiera procesar la informacin de un conjunto de alumnos y no de un solo alumno. As, la informacin de los alumnos matriculados en 3 titulaciones distintas, con 200 alumnos por titulacin, puede representarse con la siguiente matriz de registros:
0 id nombre grupo notas id nombre grupo notas id nombre grupo notas 01234567890123456789 1 ... 199 0

...

... 0123456789

75

6. ESTRUCTURAS

DE

DATOS (II): REGISTROS Y ARCHIVOS

DE

DATOS

En lenguaje C, la definicin de esta estructura de datos sera:


typedef struct { int id; char nombre[35]; char grupo; double notas[10]; } tipoAlumno; (...) tipoAlumno alumnos[3][200];

Para referirnos al grupo del vigsimo tercer alumno de la segunda titulacin emplearemos la sintaxis alumnos[1][22].grupo, mientras que la sintaxis alumnos[0][33].notas[5] hara referencia a la sexta nota de trigsimo cuarto alumno de la primera titulacin.
EJEMPLO 6.1. Desarrollar un mdulo que, recibiendo del mdulo llamador un vector de registros de 'np' poblaciones, con el nombre de cada poblacin y su censo (nmero de habitantes en unidades de millar) durante 'nd' dcadas, muestre por pantalla, para cada poblacin, su nombre y el nmero de orden de la dcada con mayor nmero de habitantes (si hay varias dcadas con el mayor nmero de habitantes, deber mostrar el nmero de orden de la primera de ellas). El nmero mximo de dcadas es 10.

M. llamador
np, nd, lPob[np].nom, lPob[np].hab[nd]

mayorCenso
MDULO mayorCenso: 1) ANLISIS: a) Datos de entrada: np: Nmero de poblaciones. Mdulo llamador (np > 0) nd: Nmero de dcadas. Mdulo llamador (nd > 0) lPob[np].nom: Nombre de cada poblacin. Mdulo llamador. lPob[np].hab[nd]: Miles de habitantes de cada poblacin en cada dcada. Mdulo llamador. b) Datos de salida: lPob[np].nom: Monitor. decada[np]: Nmero de orden de la dcada con mayor censo de cada poblacin. Monitor. c) Comentarios: Se supone que en algn mdulo ascendiente se ha definido lo siguiente: CONSTANTES MAXDEC=10 TIPOS tipoPob= nom[40]:carcter hab[MAXDEC]:reales Se utilizar una variable ndice para recorrer la lista de poblaciones y otra para recorrer los censos de cada poblacin en busca del mayor censo. Se utilizar una variable para almacenar el nmero de orden de la dcada a la que pertenece el censo mayor de cada poblacin durante cada bsqueda. 2) DISEO: a) Parte declarativa: mayorCenso(lPob[]:tipoPob, np:entero, nd:entero) VARIABLES ip,id,iMax:entero

76

6. ESTRUCTURAS

DE

DATOS (II): REGISTROS Y ARCHIVOS

DE

DATOS

b) Representacin algortmica: mayorCenso(lPob,np,nd) BLOCK for do


ip 0, np-1, 1

BLOCK for do if then iMaxid escribir (lPob[ip].nom,iMax+1)

iMax0
id 1, nd-1, 1 lPob[ip].hab[id] > lPob[ip].hab[iMax]

3) CODIFICACIN:
#define MAXDEC 10 /* Nmero mximo de dcadas */

typedef struct { char nom[40]; double hab[MAXDEC]; } tipoPob; (...) /* mayorCenso(listaPob,np,nd) */ /* Muestra, para cada poblacin, su nombre y la dcada */ /* con mayor censo. */ void mayorCenso(tipoPob listaPob[], int np, int nd) { int ip,id,iMax; for (ip=0; ip<=np-1; ip=ip+1) { iMax=0; for (id=1; id<=nd-1; id=id+1) if (listaPob[ip].hab[id] > listaPob[ip].hab[iMax]) iMax=id; printf("La poblacin %s tiene su mayor censo en la dcada %d\n", listaPob[ip].nom,iMax+1); }

(...)

6.2 ARCHIVOS DE DATOS


El manejo de grandes volmenes de informacin a menudo requiere el uso de dispositivos de almacenamiento secundario (DAS) para poder mantener dicha informacin entre distintas ejecuciones del programa. As, un programa que gestione informacin de los alumnos matriculados en diversas titulaciones, por ejemplo, debera poder almacenar en DAS la informacin sobre los alumnos pues, en caso contrario, sera necesario introducir dicha informacin cada vez que se ejecuta el programa.

77

6. ESTRUCTURAS

DE

DATOS (II): REGISTROS Y ARCHIVOS

DE

DATOS

El manejo de archivos de datos en los programas permite cubrir esta necesidad. Los archivos de datos que se estudiarn aqu permiten leer o escribir secuencialmente en DAS bloques de datos, cada uno con un nmero de bytes determinado. Estos bloques de datos suelen ser estructuras de datos complejas, como registros, arrays o arrays de registros, aunque, en general, pueden ser datos de cualquier tipo. En C, un archivo de datos se representa mediante un puntero a un valor de tipo FILE. Para declarar un archivo de datos emplearemos la siguiente sintaxis: En algoritmia:
VARIABLES fAlumnos: archivo

En C:
FILE *fAlumnos;

Distinguimos cuatro operaciones bsicas sobre archivos de datos: apertura, cierre, escritura y lectura. En C, estas operaciones se realizan mediante funciones internas que se encuentran en la biblioteca de archivo de cabecera stdio.h.

6.2.1 APERTURA DE ARCHIVOS DE DATOS


La apertura de un archivo de datos permite su uso dentro de un programa, ya que antes de leer o escribir en un archivo es necesario que este se encuentre abierto. Fundamentalmente, existen dos modos de abrir un archivo de datos: en modo lectura o en modo escritura. En C, la operacin de apertura de archivos de datos se realiza con la funcin interna fopen. Dicha funcin emplea dos parmetros de tipo cadena de caracteres: el primero, representar el nombre del archivo en DAS; y el segundo, el modo de apertura ("r" para lectura y "w" para escritura). Si la apertura se realiza con xito, esta funcin devuelve un puntero a un archivo (es decir, un puntero a un valor de tipo FILE). La apertura de un archivo en modo lectura requerir que dicho archivo exista en DAS, o en caso contrario, se producir un error de apertura y fopen devolver NULL. Por otro lado, cabe sealar que la apertura de un archivo en modo escritura eliminar del DAS el archivo si ya existiera. Por ejemplo, para abrir un archivo de datos llamado ALUMNOS.DAT en modo lectura y asignarlo a la variable archivo declarada en la seccin anterior, utilizaremos la sintaxis: fAlumnos=fopen("ALUMNOS.DAT","r"); En algoritmia, nos referiremos a la operacin de apertura de archivos con la palabra abrir.

6.2.2 CIERRE DE ARCHIVOS DE DATOS


Una vez que ha terminado de utilizarse un archivo, este debe cerrarse. Para ello, en C emplearemos la funcin interna fclose, que tiene como nico parmetro la variable de tipo archivo que representa el archivo a cerrar. Por ejemplo, para cerrar el archivo utilizado en la seccin anterior utilizaremos la sintaxis: fclose(fAlumnos); En algoritmia, nos referiremos a la operacin de cierre de archivos con la palabra cerrar.

78

6. ESTRUCTURAS DE DATOS (II): REGISTROS Y ARCHIVOS DE DATOS

6.2.3 ESCRITURA DE DATOS EN UN ARCHIVO


Una vez que abrimos un archivo en modo escritura, debemos proceder a grabar su contenido. En C, la funcin interna fwrite grabar en un archivo un nmero determinado de bloques del mismo tamao. Esta funcin utiliza cuatro parmetros: el primero, un puntero a la posicin de memoria desde donde se comenzarn a grabar los bloques de bytes al archivo; el segundo, el tamao en bytes de cada bloque; el tercero, el nmero de bloques a grabar, y el cuarto, la variable archivo que representa al archivo grabado. En C, el operador unario sizeof determina el nmero de bytes ocupado en memoria por un dato de cualquier tipo. El operando ser una expresin o un tipo y el resultado ser un valor de tipo entero igual al nmero de bytes ocupado por el valor de la expresin o por el tipo. Por ejemplo, sizeof(int) devolver el nmero de bytes que ocupa un valor de tipo int (4 bytes) mientras que sizeof(alumnos) devolver el nmero de bytes ocupado por la matriz alumnos. En algoritmia, nos referiremos a esta operacin con la palabra tamao. Por ejemplo, para grabar en el archivo ALUMNOS.DAT abierto en modo lectura la matriz alumnos de 3200 registros utilizada en la Seccin 6.1, la instruccin de escritura de dicha matriz en el archivo consistir en: fwrite(alumnos,sizeof(alumnos),1,fAlumnos); o bien fwrite(alumnos,sizeof(tipoAlumno),3*200,fAlumnos); La escritura de los datos del archivo se hace de modo secuencial, por lo que cada operacin de escritura avanzar en el archivo el nmero de bytes escritos. De este modo, cada operacin de escritura situar la informacin en el archivo a continuacin de la ltima informacin grabada. En algoritmia, nos referiremos a esta operacin con la palabra grabar.

6.2.4 LECTURA DE DATOS DE UN ARCHIVO


Tras la apertura de un archivo en modo lectura, podremos recuperar su contenido. En C, la funcin interna fread recuperar desde un archivo un nmero determinado de bloques de bytes del mismo tamao y los almacenar en memoria. Esta funcin utiliza los mismos cuatro parmetros que la funcin fwrite: el primero, un puntero a la posicin de memoria donde comenzarn a almacenarse los bloques de bytes ledos desde el archivo; el segundo, el tamao en bytes de cada bloque; el tercero, el nmero de bloques a leer, y el cuarto, la variable que representa al archivo. Por ejemplo, suponiendo que en el archivo ALUMNOS.DAT est almacenada la matriz alumnos de 3200 registros utilizada en la Seccin 6.1 y que dicho archivo se abri en modo lectura como se indic en la Seccin 6.2.1, la instruccin de lectura de dicha matriz desde el archivo consistira en: fread(alumnos,sizeof(alumnos),1,fAlumnos); o bien fread(alumnos,sizeof(tipoAlumno),3*200,fAlumnos); Al igual que la escritura, la lectura de datos se hace de modo secuencial, por lo que una operacin de lectura subsiguiente recuperar la informacin del archivo que sigue a la ya leda. En algoritmia, nos referiremos a la operacin de escritura en un archivo con la palabra recuperar. 79

También podría gustarte