|
|||||||
|
|
|
|||||
|
|
|||||||
A continuación se creará un programa que maneja la información de una serie de productos , que mediante una simulación de almacenaje en diferentes bodegas, van aumentando su stock.
Toda la información va a ser almacenada en los archivos product.dat y almacena.dat y será manipulada en estructuras de datos como colas y árboles
Bajar programa Ejecutable
Bajar codigo fuente (incluye archivos de arbol y cola)
Estructuras
Como las propiedades del producto son : { codigo , nombre , stock , precio } se crea el tipo TProducto.
typedef struct
{
int codigo;
char nombre[15];
int stock;
int precio;
} TProducto;
En algún momento vamos a simular el almacenaje, guardando información en archivo. Para eso creamos la estructura TAlmacenaje que contiene los campos : { codigo producto , numero de bodega , cantidad }
typedef struct
{
int codProducto;
int numBodega;
int cantidad;
} TAlmacenaje;
Para poder manejar colas y árboles de los dos tipos anteriores , creamos un tipo global, que contiene dos variables de cada estructura.
typedef struct
{
TProducto producto;
TAlmacenaje almacenaje;
} TGlobal;
Declaración de tipos y archivos tadCola y tadArbol
TipoC y TipoA (tipos de cola y árbol) van a ser de tipo TGlobal. A continuación se incluyen los archivos que contienen las funciones necesarias para ocupar las estructuras de datos.
typedef TGlobal TipoA; typedef TipoA TipoC; #include "tadArbin.h" #include "tadCola.h" #include "funcArbin.h"
Funciones generales
Es muy importante asegurar la existencia del archivo (aunque no contenga información), ya que posiblemente en la funciones de recorrido, se puede cometer un error fatal si no se cumple con la condición.
Para evitar lo anterior, se crea la siguiente función, que inicia un archivo según nombre y modo de apertura
Ej :
asegurarExistenciaArchivo("product.dat","a");
asegurarExistenciaArchivo("almacena.dat","w");
void asegurarExistenciaArchivo(const char *nombre_arch,const char *modo_apertura)
{
FILE *f = fopen(nombre_arch,modo_apertura);
if (f == NULL)
{
printf("\tpuntero nulo!!");
}
fclose(f);
}
| No menos importante, es fijar las tareas que debe realizar el programa y representarlo en un menú en pantalla. Para ello se crea la función menu() que retorna la opción escogida, para luego ser procesada en una sentencia del tipo switch. |
|
int menu(void)
{
printf("\n\n\tOPCIONES");
printf("\n\t--------\n\n");
printf("\t1.- Ver Lista de Productos\n");
printf("\t2.- Ingresar producto\n");
printf("\t3.- Eliminar producto\n");
printf("\t4.- Simular almacenaje\n");
printf("\t5.- Asignar stock cero\n");
printf("\t6.- Salir\n");
int opcion = 6;
printf("\n\tIngrese opcion : ");
scanf("%d",&opcion);
return opcion;
}
Funciones relacionadas con la estructura TProducto
| Para sacar a pantalla los datos en forma ordenada , creamos dos funciones que imprimen tabuladamente los nombres y valores de los campos. |
|
void tabularProducto(TProducto p)
{
printf("\t%d",p.codigo);
printf("\t%-15s",p.nombre);
printf("\t\t%d",p.stock);
printf("\t%d",p.precio);
}
/* %-15s : formato para imprimir (15) caracteres , alineados a la derecha (-) */
void tablaProducto()
{
printf("\n\n");
printf("\tcodigo\tnombre \t\tstock\tprecio\n");
printf("\t------\t---------------\t\t-----\t------");
}
|
Para leer los productos por teclado y luego almacenarlos en el archivo product.dat, se crearon
las siguentes funciones leerProducto : se encarga de verificar la existencia del producto, en caso de eliminación o creación de un registro (Los detalles se verán más adelante). guardarProducto : almacena una variable de tipo TProducto (pasada como puntero) en el archivo product.dat. |
|
TProducto leerProducto(int *existe,int eliminar = 0)
{
TProducto p;
printf("\n\n\tIngreso de producto");
printf("\n\t-------------------\n\n");
printf("\tcodigo : ");
scanf("\t%d",&(p.codigo));
if (existeProducto(p,comparacionCodigo))
{
*existe = 1;
return p;
}
if (!eliminar)
{
fflush(stdin);
printf("\tnombre : ");
gets(p.nombre);
printf("\tprecio : ");
scanf("\t%d",&(p.precio));
p.stock = 0;
}
return p;
}
void guardarProducto(TProducto *p)
{
FILE *f = fopen ("product.dat","a");
fwrite (p, sizeof(TProducto),1, f);
fclose (f);
}
Ejemplo : (Ingreso de producto)
existe = 0;
p = leerProducto(&existe);
if (!existe) guardarProducto(&p);
else
printf("\n\n\tError : el codigo ya existe!!\n");
Una de las más importantes operaciones que se deben realizar para manejar la información, es manipularla en una estructura de datos. En este caso creamos una función que pasa la información del archivo product.dat a una cola y vice-versa.
Cola traspasoArchivoProductos()
{
Cola c = inicCola();
TGlobal tmp;
TProducto aux;
FILE *f = fopen ("product.dat","r");
fread (&aux, sizeof (TProducto), 1, f);
while (!feof(f))
{
tmp.producto = aux;
adicCola(c,tmp);
fread (&aux, sizeof(TProducto), 1, f);
}
fclose(f);
return c;
}
Cola actualizarArchivoProducto(Cola c)
{
Cola aux = inicCola();
if (!vaciaCola(c))
{
FILE *f = fopen ("product.dat","w");
TGlobal tmp;
TProducto *p;
while(!vaciaCola(c))
{
tmp = infoCola(c);
p = &(tmp.producto);
fwrite (p, sizeof(TProducto),1, f);
adicCola(aux,tmp);
elimCola(c);
}
fclose (f);
destruirCola(c);
}
return aux;
}
|
Para resolver el problema de ordenar los registros, según cierto criterio, podemos utilizar la técnica
de pasar la información a un árbol binario, dependiendo de una función de comparación pasada como
parámetro (necesaria para la función insertar del TAD Arbin).
Como primer paso, creamos una función que nos permita ingresar por teclado el criterio de ordenación, luego las respectivas funciones de comparación y por último funciones que manejen las colas y los árboles, para cumplir con el objetivo. |
|
int elegirCriterioOrden()
{
printf("\n\tOrdenar por : \n");
printf("\t\t1.- nombre\n");
printf("\t\t2.- codigo\n");
printf("\t\t3.- stock\n");
printf("\t\t4.- precio\n");
printf("\n\tIngrese opcion : ");
int r = 1;
scanf("%d",&r);
return r;
}
Funciones de comparación
int productoNombreMayor(TGlobal a,TGlobal b)
{
int r = strcmp(a.producto.nombre,b.producto.nombre);
if (r > 0) return 1;
else return 0;
}
int productoCodigoMayor(TGlobal a,TGlobal b)
{
return a.producto.codigo > b.producto.codigo;
}
int productoStockMayor(TGlobal a,TGlobal b)
{
return a.producto.stock > b.producto.stock;
}
int productoPrecioMayor(TGlobal a,TGlobal b)
{
return a.producto.precio > b.producto.precio;
}
Ordenar la información en una cola según criterio
Cola ordenarCola(Cola c , int criterio = 1)
{
int (*funcCriterio)(TipoA,TipoA);
switch(criterio)
{
case 1 :
funcCriterio = productoNombreMayor;
break;
case 2 :
funcCriterio = productoCodigoMayor;
break;
case 3 :
funcCriterio = productoStockMayor;
break;
case 4 :
funcCriterio = productoPrecioMayor;
break;
default : funcCriterio = productoNombreMayor;
}
Arbin a = arbinVacio();
TGlobal tmp;
while (!vaciaCola(c))
{
tmp = infoCola(c);
a = insertarArbin(a,tmp,funcCriterio);
elimCola(c);
}
inordenArbin(a,c);
destruirArbin(a);
a = arbinVacio();
return c;
}
Mostrar tabla de productos ordenados
Cola verProductosOrdenados(Cola c)
{
TGlobal tmp;
Cola aux = inicCola();
while(!vaciaCola(c))
{
tmp = infoCola(c);
printf("\n");
tabularProducto(tmp.producto);
adicCola(aux,tmp);
elimCola(c);
}
destruirCola(c);
return aux;
}
En alguna parte del programa hay que comprobar existencia de algún producto. Para esto se crea una función generica que busca el producto en una cola, según un criterio de comparación pasado como parámetro.
int comparacionCodigo(TProducto a,TProducto b)
{
return a.codigo == b.codigo;
}
int existeProducto(TProducto p , int(*funcCriterio)(TProducto,TProducto))
{
int existe = 0;
Cola c = inicCola();
c = traspasoArchivoProductos();
while(!vaciaCola(c))
{
TGlobal tmp = infoCola(c);
if (funcCriterio(p,tmp.producto))
{
existe = 1;
break;
}
elimCola(c);
}
destruirCola(c);
return existe;
}
Si se comete un error de entrada de producto y algún registro puede estar defectuoso, implementamos una función
que elimina un registro, según un criterio de comparación (en este programa se compara por código).
void eliminarProducto(TProducto p,int (*criterioEliminacion)(TProducto,TProducto))
{
Cola c = inicCola();
c = traspasoArchivoProductos();
Cola aux = inicCola();
TGlobal tmp;
while(!vaciaCola(c))
{
tmp = infoCola(c);
if (!criterioEliminacion(p,tmp.producto))
adicCola(aux,tmp);
elimCola(c);
}
aux = actualizarArchivoProducto(aux);
destruirCola(aux);
destruirCola(c);
}
Una de las operaciones que se realizan en el programa, es realizar una simulación que asigna
un stock aleatorio en cada pasada.
Ya que en algún momento, se requiere volver atrás y tener los stock en cero, implementamos una función que
recibe una cola de productos con stock mayor o igual a cero y retorna los mismos productos con stock cero.
En el programa principal, se deberá actualizar el archivo, después de llamar a esta función.
Cola asignarStockCero(Cola c)
{
Cola aux = inicCola();
TGlobal tmp;
while(!vaciaCola(c))
{
tmp = infoCola(c);
tmp.producto.stock = 0;
elimCola(c);
adicCola(aux,tmp);
}
destruirCola(c);
return aux;
}
Funciones relacionadas con la estructura TAlmacenaje
La simulación consiste en almacenar en el archivo almacena.dat información que contiene un valor existente de código de producto , una cantidad de almacenaje y un número de bodega aleatorio.
void simulacionAlmacenaje()
{
Cola c = traspasoArchivoProductos();
FILE *f = fopen ("almacena.dat","a");
TGlobal tmp;
while(!vaciaCola(c))
{
tmp = infoCola(c);
tmp.almacenaje.cantidad = 500 + rand() % 501;
tmp.almacenaje.codProducto = tmp.producto.codigo;
tmp.almacenaje.numBodega = 1 + rand() % 10;
fwrite (&tmp.almacenaje, sizeof(TAlmacenaje),1, f);
elimCola(c);
}
fclose (f);
destruirCola(c);
}
Al igual que los productos, necesitamos pasar la información del archivo almacena.dat en una cola, para ser manipulada más fácilmente en otras funciones.
Cola traspasoArchivoAlmacena()
{
Cola c = inicCola();
TGlobal tmp;
TAlmacenaje aux;
FILE *f = fopen ("almacena.dat","r");
fread (&aux, sizeof (TAlmacenaje), 1, f);
while (!feof(f))
{
tmp.almacenaje = aux;
adicCola(c,tmp);
fread (&aux, sizeof(TAlmacenaje), 1, f);
}
fclose(f);
return c;
}
Finalmente, implementamos una función que relaciona los dos archivos, para incrementar los stock y retornar los productos actualizados en una cola.
Cola obtenerInfStock()
{
Cola c1 = traspasoArchivoProductos();
Cola c2 = NULL;
Cola aux = inicCola();
TGlobal tmp1,tmp2;
while(!vaciaCola(c1))
{
tmp1 = infoCola(c1);
c2 = traspasoArchivoAlmacena();
while(!vaciaCola(c2))
{
tmp2 = infoCola(c2);
if ( tmp2.almacenaje.codProducto == tmp1.producto.codigo )
tmp1.producto.stock += tmp2.almacenaje.cantidad;
elimCola(c2);
}
adicCola(aux,tmp1);
elimCola(c1);
}
destruirCola(c1);
destruirCola(c2);
return aux;
}
Programa principal
int main()
{
int resp = 1;
int criterio = 1;
TProducto p;
int existe;
Cola c;
asegurarExistenciaArchivo("product.dat","a");
asegurarExistenciaArchivo("almacena.dat","w");
while(resp == 1)
{
int varMenu = menu();
switch(varMenu)
{
case 1 :
criterio = elegirCriterioOrden();
tablaProducto();
c = traspasoArchivoProductos();
c = ordenarCola(c ,criterio);
c = actualizarArchivoProducto(c);
c = verProductosOrdenados(c);
destruirCola(c);
break;
case 2 :
existe = 0;
p = leerProducto(&existe);
if (!existe) guardarProducto(&p);
else
printf("\n\n\tError : el codigo ya existe!!\n");
break;
case 3 :
existe = 0;
p = leerProducto(&existe,1);
if (existe)
eliminarProducto(p,comparacionCodigo);
else
printf("\n\n\tError : el codigo no existe!!\n");
break;
case 4 :
printf("\n\n\tSimulacion realizada...\n");
simulacionAlmacenaje();
c = obtenerInfStock();
c = actualizarArchivoProducto(c);
destruirCola(c);
break;
case 5 :
printf("\n\n\tSe ha asignado 0 a todos los stock...\n");
c = obtenerInfStock();
c = asignarStockCero(c);
c = actualizarArchivoProducto(c);
destruirCola(c);
break;
case 6 :
resp = 0;
break;
}
}
return 0;
}