Estructura del Array
Un array (matriz o vector) es un conjunto finito y ordenado de elementos homogneos. La propiedad ordenado significa que el elemento primero, segundo, tercero,..., ensimo de un array puede ser identificado. Los elementos de un array son homogneos, es decir, del mismo tipo de datos. Un array puede ser compuesto de todos sus elemento de tipo entero, etc. Los arrays se conocen tambin como matrices en matemtica y tablas en clculos financieros. El tipo ms simple de array es el array unidimensional o vector (matriz de dimensin). Un vector de una dimensin denominado NOTAS que consta de n elementos se puede representar por la Figura NOTAS (1) NOTAS (2) ............. NOTAS (I) ............ NOTAS (N)
Un ``Array'' es una lista de elementos del mismo tipo (homognea), cada uno ellos identificado por un ndice. Se puede acceder a los elementos del Array (para guardar o recuperar la informacin) en cualquier orden. El Array queda definido por o el tipo bsico de elementos que aglutina, o el nmero de elementos (longitud).
Es la estructura de datos que se usa ms frecuentemente en programacin. La gestin de informacin con el Array es eficiente. De hecho, la memoria del ordenador se gestiona como un Array en los lenguajes de bajo nivel. Los Arrays se utilizan con tanta frecuencia que todos los lenguajes de programacin ofrecen algn modo para utilizarlos con facilidad. Es posible agrupar un conjunto de elementos de tipo estructura en un array. Esto se conoce como array de estructuras:
struct trabajador { char nombre[20]; char apellidos[40]; int edad; }; struct trabajador fijo[20];
As se pueden almacenar los datos de 20 trabajadores. Ejemplos sobre como acceder a los campos y sus elementos: Para ver el nombre del cuarto trabajador, fijo[3].nombre;. Para ver la tercera letra del nombre del cuarto trabajador, fijo[3].nombre[2];. Para inicializar la variable en el momento de declararla lo haremos de esta manera:
struct trabajador fijo[20]={{"Jos","Herrero Martnez",29},{"Luis","Garca Snchez",46}};
Typedef El lenguaje 'C' dispone de una declaracin llamada typedef que permite la creacin de nuevos tipos de datos. Ejemplos:
typedef int entero; entero */ entero a, b=3; /* acabamos de crear un tipo de dato llamado /* declaramos dos variables de este tipo */
Su empleo con estructuras est especialmente indicado. Se puede hacer de varias formas:
Una forma de hacerlo: struct trabajador { char nombre[20]; char apellidos[40]; int edad; }; typedef struct trabajador datos; datos fijo,temporal; Otra forma: typedef struct { char nombre[20]; char apellidos[40]; int edad; }datos; datos fijo,temporal;
FICHEROS
Aqu se ve la forma en la que se pueden almacenar los datos y s que se pueden recuperan cuando lo deseemos, aqu se estudian los distintos modos en que podemos abrir un fichero, as como las funciones para leer y escribir en l. Apertura Antes de abrir un fichero se necesita declarar un puntero de tipo FILE, con el que se trabajara durante todo el proceso. Para abrir el fichero utilizaremos la funcin fopen( ). Su sintaxis es:
FILE *puntero; puntero = fopen ( nombre del fichero, "modo de apertura" );
Donde puntero es la variable de tipo FILE, nombre del fichero es el nombre que se le dara al fichero que queremos crear o abrir. Este nombre debe ir encerrado entre comillas. Tambin podemos especificar la ruta donde se encuentra o utilizar un array que contenga el nombre del archivo ( en este caso no se pondrn las comillas ). Algunos ejemplos:
puntero=fopen("DATOS.DAT","r"); puntero=fopen("C:\\TXT\\SALUDO.TXT","w");
Un archivo puede ser abierto en dos modos diferentes, en modo texto o en modo binario. A continuacin lo veremos con ms detalle. Modo texto
w w+ a a+ r r+ crea un fichero de escritura. Si ya existe lo crea de nuevo. crea un fichero de lectura y escritura. Si ya existe lo crea de nuevo. abre o crea un fichero para aadir datos al final del mismo. abre o crea un fichero para leer y aadir datos al final del mismo. abre un fichero de lectura. abre un fichero de lectura y escritura.
Modo binario
wb w+b ab crea un fichero de escritura. Si ya existe lo crea de nuevo. crea un fichero de lectura y escritura. Si ya existe lo crea de nuevo. abre o crea un fichero para aadir datos al final del mismo.
a+b rb r+b
abre o crea un fichero para leer y aadir datos al final del mismo. abre un fichero de lectura. abre un fichero de lectura y escritura.
La funcin fopen devuelve, como ya hemos visto, un puntero de tipo FILE. Si al intentar abrir el fichero se produjese un error ( por ejemplo si no existe y lo estamos abriendo en modo lectura ), la funcin fopen devolvera NULL. Por esta razn es mejor controlar las posibles causas de error a la hora de programar. Un ejemplo:
FILE *pf; pf=fopen("datos.txt","r"); if (pf == NULL) printf("Error al abrir el fichero");
freopen( ) Esta funcin cierra el fichero apuntado por el puntero y reasigna este puntero a un fichero que ser abierto. Su sintaxis es:
freopen(nombre del fichero,"modo de apertura",puntero);
donde nombre del fichero es el nombre del nuevo fichero que queremos abrir, luego el modo de apertura, y finalmente el puntero que va a ser reasignado. Cierre Una vez que hemos acabado nuestro trabajo con un fichero es recomendable cerrarlo. Los ficheros se cierran al finalizar el programa pero el nmero de estos que pueden estar abiertos es limitado. Para cerrar los ficheros utilizaremos la funcin fclose( );. Esta funcin cierra el fichero, cuyo puntero le indicamos como parmetro. Si el fichero se cierra con xito devuelve 0.
fclose(puntero);
Un ejemplo ilustrativo aunque de poca utilidad:
FILE *pf; pf=fopen("AGENDA.DAT","rb");
if ( pf == NULL ) printf ("Error al abrir el fichero"); else fclose(pf);
Escritura y lectura A continuacin veremos las funciones que se podrn utilizar dependiendo del dato que queramos escribir y/o leer en el fichero. Un caracter
fputc( variable_caracter , puntero_fichero );
Escribimos un caracter en un fichero ( abierto en modo escritura ). Un ejemplo:
FILE *pf; char letra='a'; if (!(pf=fopen("datos.txt","w"))) /* otra forma de controlar si se produce un { printf("Error al abrir el fichero"); exit(0); /* abandonamos el programa */ } else fputc(letra,pf); fclose(pf);
error */
fgetc( puntero_fichero );
Lee un caracter de un fichero ( abierto en modo lectura ). Deberemos guardarlo en una variable. Un ejemplo:
FILE *pf; char letra; if (!(pf=fopen("datos.txt","r"))) /* controlamos si se produce un error */ { printf("Error al abrir el fichero"); exit(0); /* abandonamos el programa */ } else { letra=fgetc(pf); printf("%c",letra); fclose(pf); }
Un nmero entero
putw( variable_entera, puntero_fichero );
Escribe un nmero entero en formato binario en el fichero. Ejemplo:
FILE *pf; int num=3; if (!(pf=fopen("datos.txt","wb"))) /* controlamos si se produce un error */ { printf("Error al abrir el fichero"); exit(0); /* abandonamos el programa */ } else { fputw(num,pf); /* tambin podamos haber hecho directamente: fputw(3,pf); */ fclose(pf); }
getw( puntero_fichero );
Lee un nmero entero de un fichero, avanzando dos bytes despus de cada lectura. Un ejemplo:
FILE *pf; int num; if (!(pf=fopen("datos.txt","rb"))) /* controlamos si se produce un error */ { printf("Error al abrir el fichero"); exit(0); /* abandonamos el programa */ } else { num=getw(pf); printf("%d",num); fclose(pf); }
Una cadena de caracteres
fputs( variable_array, puntero_fichero );
Escribe una cadena de caracteres en el fichero. Ejemplo:
FILE *pf; char cad="Me llamo Vicente"; if (!(pf=fopen("datos.txt","w"))) /* controlamos si se produce un error */ { printf("Error al abrir el fichero"); exit(0); /* abandonamos el programa */ } else { fputs(cad,pf); /* o tambin as: fputs("Me llamo Vicente",pf); */ fclose(pf); }
fgets( variable_array, variable_entera, puntero_fichero );
Lee una cadena de caracteres del fichero y la almacena en variable_array. La variable_entera indica la longitud mxima de caracteres que puede leer. Un ejemplo:
FILE *pf; char cad[80]; if (!(pf=fopen("datos.txt","rb"))) /* controlamos si se produce un error */ { printf("Error al abrir el fichero"); exit(0); /* abandonamos el programa */ } else { fgets(cad,80,pf); printf("%s",cad); fclose(pf); }
Con formato
fprintf( puntero_fichero, formato, argumentos);
Funciona igual que un printf pero guarda la salida en un fichero. Ejemplo:
FILE *pf; char nombre[20]="Santiago"; int edad=34; if (!(pf=fopen("datos.txt","w"))) /* controlamos si se produce un error */ { printf("Error al abrir el fichero"); exit(0); /* abandonamos el programa */ } else { fprintf(pf,"%20s%2d\n",nombre,edad); fclose(pf); }
fscanf( puntero_fichero, formato, argumentos );
Lee los argumentos del fichero. Al igual que con un scanf, deberemos indicar la direccin de memoria de los argumentos con el smbolo & ( ampersand ). Un ejemplo:
FILE *pf; char nombre[20]; int edad; if (!(pf=fopen("datos.txt","rb"))) /* controlamos si se produce un error */ { printf("Error al abrir el fichero"); exit(0); /* abandonamos el programa */ } else { fscanf(pf,"%20s%2d\",nombre,&edad); printf("Nombre: %s Edad: %d",nombre,edad); fclose(pf); }
Estructuras
fwrite( *buffer, tamao, n de veces, puntero_fichero );
Se utiliza para escribir bloques de texto o de datos, estructuras, en un fichero. En esta funcin, *buffer ser la direccin de memoria de la cul se recogern los datos;tamao, el tamao en bytes que ocupan
esos datos y n de veces, ser el nmero de elementos del tamao indicado que se escribirn.
fread( *buffer, tamao, n de veces, puntero_fichero );
Se utiliza para leer bloques de texto o de datos de un fichero. En esta funcin, *buffer es la direccin de memoria en la que se almacenan los datos; tamao, el tamao en bytes que ocupan esos datos y n de veces, ser el nmero de elementos del tamao indicado que se leern. Puedes encontrar ejemplos sobre la apertura y cierre de ficheros, as como de la lectura y escritura de datos, en el archivo IMAGECAT.C. Se trata de un programa que crea un catlogo en formato HTML a partir de las imgenes que se encuentran en un directorio determinado.
Otras funciones para ficheros
rewind( puntero_fichero );
Sita el puntero al principio del archivo.
fseek( puntero_fichero, long posicion, int origen );
Sita el puntero en la posicion que le indiquemos. Como origen podremos poner:
0 o SEEK_SET, el principio del fichero 1 o SEEK_CUR, la posicin actual 2 o SEEK_END, el final del fichero
rename( nombre1, nombre2 );
Su funcin es exactamente la misma que la que conocemos en MSDOS. Cambia el nombre del fichero nombre1 por un nuevo nombre, nombre2.
remove( nombre );
Como la funcin del DOS del, podremos eliminar el archivo indicado en nombre.
Deteccin de final de fichero
feof( puntero_fichero );
Siempre deberemos controlar si hemos llegado al final de fichero cuando estemos leyendo, de lo contrario podran producirse errores de lectura no deseados. Para este fin disponemos de la funcin feof( ). Esta funcin retorna 0 si no ha llegado al final, y un valor diferente de 0 si lo ha alcanzado. Pues con esto llegamos al final del tema. Espero que no haya sido muy pesado. No es necesario que te aprendas todas las funciones de memoria. Cntrate sobre todo en las funciones fputs( ), fgets( ), fprintf( ), fwrite( ) y fread( ). Con estas cinco se pueden gestionar los ficheros perfectamente. Funciones Como veremos despus, la gestin dinmica memoria se realiza mediante estructuras dinmicas de datos. Fjate que se repite la palabra dinmica. Estas estructuras se diferencian de las estticas ( arrays y estructuras ), en que no tienen un tamao fijo, es decir, no tenemos que indicar su tamao al declararlas, sino que podremos aumentarlo o disminuirlo en tiempo de ejecucin, cuando se est ejecutando la aplicacin. Como puedes ver, las estructuras dinmicas son de gran utilidad. A continuacin veremos las funciones que se encargan de reservar y liberar memoria durante la ejecucin, que se encuentran en la librera alloc.h:
malloc( tamao ); Esta funcin reserva en memoria una zona de tamao bytes, y devuelve un puntero al inicio de esa zona. Si no hubiera suficiente memoria retornara NULL. Ms adelante veremos algunos ejemplos. free( puntero ); Esta funcin libera de la memoria la zona que habamos reservado anteriormente con la funcin malloc. Estructuras dinmicas de datos En funcin de la forma en que se relacionan existen varios tipos de estructuras de datos. Este tipo de estructuras son autorreferenciadas, es decir, contienen entre sus campos un puntero de su mismo tipo. Las ms utilizadas son:
- pilas - colas - listas
Las pilas Este tipo de estructuras se caracteriza porque todas las operaciones se realizan en el mismo lado. Es de tipo LIFO ( Last In First Out ), el ltimo elemento en entrar es el primero en salir. /* Ejemplo de una pila. */ #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <alloc.h>
void insertar(void); void extraer(void); void visualizar(void); struct pila { char nombre[20]; struct pila *ant; }*CAB=NULL,*AUX=NULL; main() /* Rellenar, extraer y visualizar */ { char opc; do { clrscr(); /* borramos la pantalla */ gotoxy(30,8); /* columna 30, fila 8 */ printf("1.- Insertar"); gotoxy(30,10); printf("2.- Extraer"); gotoxy(30,12); printf("3.- Visualizar la pila"); gotoxy(30,14); printf("4.- Salir"); opc=getch( ); switch(opc) {
case '1': insertar( ); break; case '2': extraer( ); break; case '3': visualizar( ); } }while (opc!='4'); }
void insertar(void) { AUX=(struct pila *)malloc(sizeof(struct pila)); clrscr(); printf("Nombre: "); gets(AUX->nombre); if (CAB==NULL) { CAB=AUX; AUX->ant=NULL; } else {
AUX->ant=CAB; CAB=AUX; } }
void extraer(void) { if (CAB==NULL) return; AUX=CAB; CAB=CAB->ant; free(AUX); }
void visualizar(void) { if (CAB==NULL) return; clrscr(); AUX=CAB; while (AUX!=NULL) { printf("Nombre: %s\n",AUX->nombre); AUX=AUX->ant; } getch( ); }
La estructura tipo que utilizaremos ser sta:
struct pila { tipo variables; struct pila *ant; }*CAB=NULL,*AUX=NULL;
donde tipo variables sern las diferentes variables que guardaremos en la estructura, struct pila *ant es un puntero que apunta al elemento de tipo pila introducido anteriormente, *CAB ser donde guardaremos el ltimo elemento insertado en la pila y *AUX nos servir para guardar elementos temporalmente y para recorrer la pila al visualizarla. Antes de insertar un elemento, deberemos comprobar si la pila est vaca o no. Si lo estuviera deberemos insertar el primer elemento:
CAB=AUX; CAB->ant=NULL;
Si ya hubiera algn elemento crearemos uno nuevo apuntado por AUX y haremos que AUX->ant apunte a CAB, que en este momento contiene la direccin del elemento insertado anteriormente. Tras esto haremos que CAB apunte al ltimo elemento insertado, que ser la nueva cabeza de la pila:
AUX->ant=CAB; CAB=AUX;
Para extraer un elemento de la pila deberemos hacer que AUX apunte a la misma direccin que CAB, despus haremos que CAB apunte a CAB->ant, con lo que el elemento anterior pasar a ser la cabeza de la pila. Tras esto, solo queda liberar la memoria de la zona apuntada por AUX. No olvides controlar si existe algn elemento ( si CAB es igual aNULL la pila est vaca ):
if (CAB==NULL) return; AUX=CAB; CAB=CAB->ant; free(AUX);
Por ltimo, para visualizar los elementos de la pila, haremos que el puntero auxiliar AUX apunte a la cabeza de la pila, o sea, a CAB. Tras esto iremos visualizando el contenido de la pila, haciendo que AUX tome
la direccin de AUX->ant, mientras AUX sea distinto de NULL. Tambin es importante controlar que la pila no est vaca.
if (CAB==NULL) return; AUX=CAB; while (AUX!=NULL) { printf("%s",AUX->nombre); AUX=AUX->ant; };
Estructura grfica de una pila:
Las colas Este tipo de estructuras se caracteriza porque insertamos los elementos por un lado y los extraemos por el otro lado. Es de tipo FIFO ( First In First Out ), el primer elemento en entrar es el primero en salir. Para gestionar la cola utilizaremos 3 punteros ( para la pila solo eran necesarios 2 ).
* Ejemplo de una cola. */ #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <alloc.h> void insertar(void); void extraer(void); void visualizar(void);
struct cola { char nombre[20]; struct cola *sig; }*CAB=NULL,*AUX=NULL,*FIN=NULL; main() /* Rellenar, extraer y visualizar */ { char opc; do { clrscr(); gotoxy(30,8); printf("1.- Insertar"); gotoxy(30,10); printf("2.- Extraer"); gotoxy(30,12); printf("3.- Visualizar la cola"); gotoxy(30,14); printf("4.- Salir"); opc=getch( ); switch(opc) { case '1': insertar( ); break; case '2': extraer( ); break; case '3': visualizar( ); } }while (opc!='4'); } void insertar(void) { AUX=(struct cola *)malloc(sizeof(struct cola)); clrscr(); printf("Nombre: "); gets(AUX->nombre); AUX->sig=NULL; if (FIN==NULL) FIN=CAB=AUX; else { FIN->sig=AUX; FIN=AUX; } } void extraer(void) {
if (CAB==NULL) return; AUX=CAB; CAB=CAB->sig; free(AUX); } void visualizar(void) { if (CAB==NULL) return; clrscr(); AUX=CAB; while (AUX!=NULL) { printf("Nombre: %s\n",AUX->nombre); AUX=AUX->sig; } getch(); }
La estructura que utilizaremos ser:
struct cola { tipo variables; struct cola *sig; }*CAB=NULL,*AUX=NULL,*FIN=NULL;
donde tipo variables sern las diferentes variables que guardaremos en la estructura, struct cola *sig es un puntero que apunta al elemento de tipo cola introducido a continuacin, *CAB ser donde guardaremos el primer elemento insertado en la cola, *AUX nos servir para guardar elementos temporalmente y para recorrer la cola al visualizarla y *FIN tomar la direccin del ltimo elemento insertado. Antes de insertar un elemento, deberemos comprobar si la cola est vaca o no. Si lo est deberemos insertar el primer elemento:
if (FIN==NULL) CAB=FIN=AUX;
Si ya existiera algn elemento haremos que FIN->sig apunte al elemento de AUX y a continuacin haremos que FIN tome la direccin de AUX, con lo que FIN apuntar al ltimo elemento insertado.
FIN->sig=AUX; FIN=AUX;
Para extraer un elemento de la cola haremos que el puntero auxiliar AUX tome la direccin del primer elemento insertado, que hemos guardado en CAB. Tras esto haremos queCAB apunte a CAB>sig, es decir, que tome la direccin del segundo elemento insertado, que ahora pasar a ser el primero. Luego liberaremos la zona de memoria apuntada porAUX:
AUX=CAB; /* Deberemos controlar que no est vaca: if (CAB==NULL) return; */ CAB=CAB->sig; free(AUX);
Para visualizar la cola comprobaremos que existan elementos, esto es, que FIN sea distinto de NULL. Hecho esto asignaremos a AUX la direccin de CAB e iremos recorriendo la cola hasta que AUX sea igual a NULL.
AUX=CAB; /* Deberemos controlar que no est vaca: if (CAB==NULL) return; */ while(AUX!=NULL) { printf("%s",AUX->nombre); AUX=AUX->sig; }
Estructura grfica de una cola:
Las listas Este tipo de estructuras se caracteriza porque los elementos estn enlazados entre s, de manera que adems de las acciones habituales de
insertar, extraer y visualizar tambin podremos buscar un elemento. Para gestionar la lista utilizaremos 4 punteros.
/* Ejemplo de una lista. */ #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <alloc.h> void insertar(void); void extraer(void); void visualizar(void); struct lista { int num; struct lista *sig; }*CAB=NULL,*AUX=NULL,*F=NULL,*P=NULL; main() /* Rellenar, extraer y visualizar */ { char opc; do { clrscr( ); gotoxy(30,8); printf("1.- Insertar"); gotoxy(30,10); printf("2.- Extraer"); gotoxy(30,12); printf("3.- Visualizar la lista"); gotoxy(30,14); printf("4.- Salir"); opc=getch( ); switch(opc) { case '1': insertar( ); break; case '2': extraer( ); break; case '3': visualizar( ); } }while (opc!='4'); } /* A continuacin insertaremos el elemento que vamos a crear en la posicin que le corresponda,
teniendo en cuenta que la lista deber quedar ordenada de menor a mayor. El puntero P comprueba si el campo num de un elemento es menor que el campo num del elemento introducido. El puntero F se quedar apuntando al elemento de la posicin anterior al elemento que hemos insertado */ void insertar(void) { AUX=(struct lista *)malloc(sizeof(struct lista)); clrscr( ); printf("Introduce un nmero: "); scanf("%d",&AUX->num); AUX->sig=NULL; if (CAB==NULL) CAB=AUX; else if (CAB->num > AUX->num) { AUX->sig=CAB; CAB=AUX; } else { P=F=CAB; while (P->num < AUX->num && P!=NULL) { if (P==CAB) P=P->sig; else { P=P->sig; F=F->sig; } } AUX->sig=F->sig; F->sig=AUX; } } void extraer(void) { int var; if (CAB==NULL) return; clrscr( ); printf("Introduce el nmero a extraer: "); scanf("%d",&var); if (CAB->num==var) { P=CAB; CAB=CAB->sig; free(P); } else {
P=F=CAB; while (P->num != var && P!=NULL) { if (P==CAB) P=P->sig; else { P=P->sig; F=F->sig; } } if (P==NULL) return; F->sig=P->sig; free(P); } } void visualizar(void) { if (CAB==NULL) return; clrscr( ); AUX=CAB; while (AUX!=NULL) { printf("Nmero: %d\n",AUX->num); AUX=AUX->sig; } getch( ); }
La estructura que utilizaremos ser:
struct lista { tipo variables; struct lista *sig; }*CAB=NULL,*AUX=NULL,*F=NULL,*P=NULL;
donde tipo variables sern las variables que guardaremos en la estructura, struct lista *sig es un puntero que apunta al elemento de tipo lista introducido a continuacin,*CAB ser donde guardaremos el primer elemento de la lista, *AUX nos servir para guardar elementos temporalmente y para recorrer la lista al visualizarla, *P para comparar los valores introducidos y ordenarlos, y *F, que apuntar al elemento anterior al ltimo introducido. Antes de insertar un elemento, deberemos comprobar si la lista est vaca o no. Si lo est deberemos insertar el primer elemento:
if (CAB==NULL) CAB=AUX;
Si ya existiera algn elemento haremos que P y F apunten al primero de la lista. Si el elemento introducido fuera menor que el primero de la lista, haramos que el nuevo elemento pasara a ser el primero, y el que hasta ahora era el primero, pasara a ser el segundo.
if (AUX->num < CAB->num){ AUX->sig=CAB; CAB=AUX; }
Para extraer un elemento de la lista solicitaremos un nmero, si el nmero introducido se corresponde con el campo num de uno de los elementos, ste ser extrado de la lista. Deberemos controlar que la lista no est vaca y que el elemento con el nmero solicitado exista. Fjate en el ejemplo, en la funcin extraer. Si CAB es igual a NULL, ser que la lista est vaca, y si P es igual a NULL al salir del while significar que no se ha encontrado ningn elemento que contenga el nmero introducido. Para visualizar la lista comprobaremos que existan elementos, es decir, que CAB sea distinto de NULL. Hecho esto asignaremos a AUX la direccin de CAB e iremos recorriendo la lista mientras AUX sea distinto de NULL.
if (CAB==NULL) return; AUX=CAB; while(AUX!=NULL) { printf("%d",AUX->num); AUX=AUX->sig; }
Estructura grfica de una lista: