Ejemplo agenda


Los siguientes códigos pertenecen al programa agenda. Como su nombre indica es una agenda, muy básica. Está dividida en cuatro archivos:

  • main.c
  • structAgendaReg.c
  • structAgendaReg.h
  • burbuja2.c
Para compilar este programa con gcc:
gcc main.c structAgenda.c burbuja2.c -o agendaExe

//Archivo: main.c
/*
Programa: Agenda.
Fecha: 03/12/2016

Este programa lleva el control de contactos de una agenda electrónica pudiendo añadir. El programa guarda los registros en un archivo de datos, desde donde los recuperará cada vez que se inicia el programa. Se pueden ordenar los registros por número de registro o por nombre.
*/

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include"structAgendaReg.h"


int main(void)
{
      FILE *fich;
      int num_reg;
      int i,j;
      int YN;
      int basura;
      _contacto *pAux;
      primero = NULL;
      ultimo = NULL;
  
  //Se abre el archivo de datos para lectura o se crea si no existe
  if((fich = abrir_datos(&num_reg)) == NULL){
  puts("Error en la lectura de disco");
  exit(2);
  return 2;
  }
 
    fclose(fich);   //Se cierra el archivo tras recuperar los datos.
  
    num_contactos = num_reg; //igualamos el total de contactos con el total de
      //registros leidos.
    menu();
    scanf("%d",&YN);

    while(YN != 0){
     switch(YN){

     case 1: //añadir contacto
     if(!num_contactos){
     add_first_contacto();
     }
     else{
     add_contacto();
     }
     fflush(stdin);
     break;

     case 2: //ver contactos
     menu();
     pAux = primero;
     while(pAux != NULL){
     printf("%d\t%s   \t\t%s   \t\t%s   \t%s\n",pAux->num_reg,pAux->nombre,pAux->apell,pAux
                   ->fechaCumple,pAux->tlf);
     pAux = pAux->sigu;
     }
       printf("-------------------------------------------------------------------------------------\n"); 
     if(pAux == NULL){
     printf("%d registros guardados\n",num_reg);
     }
     break;

     case 3: //guardar en archivo datos.dat
     if((fich = fopen("datos.dat","w"))==NULL){
     puts("Imposible abrir el archivo datos para guardar los registros");
     puts("Saliendo del programa");
     exit(2);
     return 2;
     }
    
     pAux = primero;
     fprintf(fich,"%d\n",num_contactos);
     while(pAux != NULL){
     fprintf(fich,"%s\n",pAux->nombre);
fprintf(fich,"%s\n",pAux->apell);
fprintf(fich,"%s\n",pAux->fechaCumple);
fprintf(fich,"%s\n",pAux->tlf);
pAux = pAux->sigu;
}
     break;

     case 4: //ordenar
     system("clear");
     menu();
     puts("Selecciones el campo de ordenación \"1 Número de registro  2 Nombre\"");
     scanf("%d",&j);
pAux = primero;
     for(i=0;i<num_contactos;i++){
    
     while(pAux->sigu != NULL){
     burbuja(pAux,j);
     pAux = pAux->sigu;
     }
     pAux = primero->sigu;
     }
     break;
     default:
    
     break;
     }
     puts("Pulsa [ENTER] para continuar");
     basura = getc(stdin); //Recoge del buffer el último ENTER
     basura = getc(stdin);
     menu();
scanf("%d",&YN);
     if(YN < 0 || YN >4)
     YN = 2;
    }
      
    return 0;
}


//archivo: structAgendaReg.c
#include<strings.h>
#include<stdio.h>
#include<stdlib.h>
#include"structAgendaReg.h"

void add_contacto(void){
_contacto *auxi;
_contacto *nuevo;
//pedimos memoria en el heap para albergar un nuevo contacto
nuevo = (_contacto *)malloc(sizeof(_contacto));

if(nuevo == NULL)  //Si no se consigue espacio en memoria devuelve NULL
exit(1);
nuevo->num_reg = (num_contactos += 1);
printf("Datos del nuevo contacto\n");
printf("Nombre: ");
scanf("%s",nuevo->nombre);
printf("Primer apellido: ");
scanf("%s",nuevo->apell);
printf("Fecha de nacimiento: 2 dígitos por dato\n");
printf("\tDia: ");
scanf("%d",&nuevo->fecha.dia);
printf("\tMes: ");
scanf("%d",&nuevo->fecha.mes);
printf("\tAño: ");
scanf("%d",&nuevo->fecha.anio);
validarFecha(nuevo->fecha.dia, nuevo->fecha.mes, nuevo->fecha.anio,nuevo->fechaCumple);
printf("Teléfono de contacto: ");
scanf("%s",nuevo->tlf);
//Añadimos al final
ultimo->sigu = nuevo;   //ultimo apunta al nuevo
nuevo->sigu = NULL;   //nuevo a punta a null
auxi = ultimo;        //guardamos el contenido de ultimo en aux
ultimo = nuevo;       //ahora ultimo vale nuevo
nuevo = auxi;          //y pasamos aux (antiguo ultimo) a nuevo
}

void validarFecha(int dia, int mes, int anio, char *fecha){
char day[4], month[4];
if(dia<10)
sprintf(day,"0%d",dia);
else
sprintf(day,"%d",dia);
if(mes<10)
sprintf(month,"0%d",mes);
else
sprintf(month,"%d",mes);
sprintf(fecha,"%s/%s/%d",day,month,anio);
}

void add_first_contacto(void){
_contacto *nuevo;
nuevo = (_contacto *)malloc(sizeof(_contacto));
if(nuevo == NULL)
exit(1);
nuevo->num_reg = num_contactos;
puts("Datos del nuevo contacto");
printf("Nombre: ");
scanf("%s",nuevo->nombre);
printf("Primer apellido: ");
scanf("%s",nuevo->apell);
printf("Fecha de nacimiento: \n");
printf("\tDia: ");
scanf("%d",&nuevo->fecha.dia);
printf("\tMes: ");
scanf("%d",&nuevo->fecha.mes);
printf("\tAño: ");
scanf("%d",&nuevo->fecha.anio);
validarFecha(nuevo->fecha.dia, nuevo->fecha.mes, nuevo->fecha.anio,nuevo->fechaCumple);
//scanf("%s",nuevo->fechaCumple);
printf("Teléfono de contacto: ");
scanf("%s",nuevo->tlf);
//Si no hay ningún contacto aún entra en el if
nuevo->sigu = NULL;
if(primero == NULL){
primero = nuevo;
ultimo  = nuevo;
num_contactos = 1;
}

}

void menu(void){
     system("clear");
     printf("1 Añadir contacto\t 2 Ver contactos\t 3 Guardar\t 4 Ordenar\t0 Salir\n\n ");
     printf("reg.\tNombre   \t\tApellido\t\tFecha Nac.\tTlf contacto\n");
     printf("-------------------------------------------------------------------------------------\n");
}

FILE * abrir_datos(int *registros){

FILE *f;
_contacto *auxi;
_contacto *nuevo;
int i;
    //Se intenta abrir el archivo de datos para lectura
    if((f = fopen("datos.dat","r")) == NULL){
        puts("El fichero datos.dat no existe");
     puts("Se procede a crear el archivo de datos datos.dat");
    
     if((f = fopen("datos.dat","w")) == NULL){
     puts("Imposible crear el archivo de datos datos.dat");
     puts("Compruebe que el disco duro no esté lleno y que tiene los permisos necesarios");
    
     return NULL;
    
     }
     else{
        //Una vez creado se escribe 0.
     fprintf(f,"%d",0);
     //se cierra el archivo para escritura y se vuelve a abrir para lectura
     fclose(f);
            if((f = fopen("datos.dat","r")) == NULL){
       puts("Imposible abrir el archivo datos.dat para lectura de registros");
       puts("El programa se cerrará");
      
       return NULL;
       }
     }
    }
    //Con el archivo de datos abierto para lectura se procede a leer el primer int
    fscanf(f,"%d",registros);

    //Si hay registros los lee
    if(*registros){
       for(i = 0; i < *registros; i++){
     nuevo = (_contacto *)malloc(sizeof(_contacto));

if(nuevo == NULL)
exit(1);

nuevo->num_reg = i+1;

fscanf(f,"%s",nuevo->nombre);

fscanf(f,"%s",nuevo->apell);
fscanf(f,"%s",nuevo->fechaCumple);

fscanf(f,"%s",nuevo->tlf);
//Se  comprueba si es el primer registro.
if(primero == NULL){
nuevo->sigu = NULL;
primero = nuevo;
ultimo  = nuevo;
num_contactos = 1;
}
else{
//Añadimos al final
ultimo->sigu = nuevo;       //ultimo apunta al nuevo
nuevo->sigu = NULL;       //nuevo a punta a null
auxi = ultimo;                   //guardamos el contenido de ultimo en aux
ultimo = nuevo;                //ahora ultimo vale nuevo
nuevo = auxi;                   //y pasamos aux (antiguo ultimo) a nuevo
num_contactos += 1;       //contacto totales almacenados en memoria
     }
     }

    }
    return f;

}


//Archivo: burbuja2.c
/*Esta función ordena los registros según la disposición dada por el cliente
Las opciones de ordenación son:
  1. por registro (por defecto)
  2. por nombre
*/

int cmpWord(char *, char *);
int cmpInt(int, int);

void burbuja(_contacto *ele1, int modo)
{
int resp;
_contacto *aux2;
aux2 = (_contacto *)malloc(sizeof(_contacto));

if(ele1 != NULL){
if(modo == 2) //Ordenación por nombre
resp = cmpWord(ele1->nombre, ele1->sigu->nombre);
if(modo == 1)//Ordenación por número de registro
resp = cmpInt(ele1->num_reg, ele1->sigu->num_reg);
if(resp == 1){ 

strcpy(aux2->nombre,   ele1->nombre);
strcpy(aux2->apell,    ele1->apell);
strcpy(aux2->fechaCumple, ele1->fechaCumple);
aux2->num_reg =    ele1->num_reg;

strcpy(ele1->nombre,       ele1->sigu->nombre);
strcpy(ele1->apell,        ele1->sigu->apell);
strcpy(ele1->fechaCumple,  ele1->sigu->fechaCumple);
ele1->num_reg =            ele1->sigu->num_reg;

strcpy(ele1->sigu->nombre,   aux2->nombre);
strcpy(ele1->sigu->apell,   aux2->apell);
strcpy(ele1->sigu->fechaCumple,aux2->fechaCumple);
ele1->sigu->num_reg =    aux2->num_reg;

}
}
}

int cmpWord( char *elem1 , char *elem2)
{
int resp = strcmp(elem1, elem2);
if(resp < 0) return -1; //elem1 es menor que elem2
if(resp == 0) return 0; //son iguales
return 1;       //elem1 es mayor que elem2

}

int cmpInt(int a, int b)
{
if(a<b)  return -1;
if(a==b)return 0;
return 1;
}

//Archivo: structAgendaReg.h
/*
Estructura de datos para la base de datos de AGENDA
Variables globales y declaración de funciones
*/

#ifndef RegistroAgenda

#define RegistroAgenda 1

struct date{
int dia;
int mes;
int anio;
};

typedef struct reg_persona{
char nombre[20];
char apell[20];
char fechaCumple[15];
struct date fecha;
char tlf[20];
int num_reg;
struct reg_persona *sigu;
}_contacto;

_contacto *primero;
_contacto *ultimo;
int num_contactos;

void validarFecha(int, int, int, char *);
void add_first_contacto(void);
void add_contacto(void);
void menu(void);
FILE * abrir_datos(int *);
void burbuja(_contacto *, int);

#endif


La salida por la terminal se ve así:


Al igual que en los otros ejemplos, invito a quien le apetezca, a mejorar el programa, añadiendo funciones al menú, por ejemplo, borrado de un registro, cambiando la interfaz o mejorando el sistema de ordenación, como sabemos el método de la burbuja no es el más adecuado cuando se tienen un gran número de registros a ordenar. Otra posible mejora podría ser la validación de fechas, este ejemplo se limita a poner un cero delante de los número menores a 10, para que tengan dos dígitos.