Código
#include <stdio.h> /* print, scanf */ #include <string.h> #include <stdlib.h> /* system */ #include <locale.h> /* setlocale */ #define MAX 80 #define VALOR_CENTINELA -1 /* Estructuras */ struct producto { int codigo; char nombre[MAX]; float costo; float precio; int cantidad; }; typedef struct producto Producto; /* Opciones del Menú */ void menuPrincipal(); void menuInsertar(); void menuBuscar(); void menuEliminar(); void menuMostrar(); void menuModificar(); void menuEliminarFisica(); /* Funciones para manejar el archivo directamente */ Producto *obtenerProductos(int *n); /* Obtiene un vector dinámico de productos */ char existeProducto(int codigoProducto, Producto *producto); /* Busca si existe el producto en el archivo de productos */ char insertarProducto(Producto producto); /* Inserta el producto al final del archivo */ char eliminarProducto(int codigoProducto); /* Eliminar el producto de código codigoProducto del archivo */ char eliminacionFisica(); /* Realiza la eliminación física de registros inválidos del archivo de productos */ char modificarProducto(Producto producto); /* Modifica el producto en el archivo */ char guardarReporte(); /* Genera un archivo TXT con el reporte de los productos */ /* Función de lectura de cadenas */ int leecad(char *cad, int n); /* Titular del programa */ void tituloPrincipal(); char linea[MAX]; int main() { menuPrincipal(); return 0; } void menuPrincipal() { char repite = 1; int opcion = -1; /* Cuando el usuario ingresa texto en lugar de ingresar una opción. El programa no modifica el valor de opcion. En ese caso, no se debe de ingresar a ninguno de los case, por eso se está inicializando la variable opcion con un valor que no permita ejecutar ningún case. Simplemente, volver a interar y pedir nuevamente la opción. */ do { tituloPrincipal(); /* Lectura segura de un entero */ leecad(linea, MAX); switch (opcion) { case 1: menuInsertar(); break; case 2: menuMostrar(); break; case 3: menuEliminar(); break; case 4: menuBuscar(); break; case 5: menuModificar(); break; case 6: menuEliminarFisica(); break; case 7: repite = 0; break; } } while (repite); } void menuInsertar() { Producto producto; int codigoProducto = 0; char repite = 1; char respuesta[MAX]; do { tituloPrincipal(); /* Se pide el código del producto a insertar */ leecad(linea, MAX); /* Se verifica que el producto no haya sido almacenado anteriormente */ if (!existeProducto(codigoProducto, &producto)) { producto.codigo = codigoProducto; /* Se piden los demás datos del producto a insertar */ leecad(producto.nombre, MAX); leecad(linea, MAX); leecad(linea, MAX); leecad(linea, MAX); /* Se inserta el producto en el archivo */ if (insertarProducto(producto)) { } else { } } else { /* El producto ya existe, no puede ser insertado. */ } leecad(respuesta, MAX); repite = 0; } } while (repite); } void menuBuscar() { Producto producto; int codigoProducto; char repite = 1; char respuesta[MAX]; do { tituloPrincipal(); /* Se pide el código del producto a buscar */ leecad(linea, MAX); /* Se verifica que el producto a buscar, exista */ if (existeProducto(codigoProducto, &producto)) { /* Se muestran los datos del producto */ } else { /* El producto no existe */ } leecad(respuesta, MAX); repite = 0; } } while (repite); } void menuEliminar() { Producto producto; int codigoProducto; char repite = 1; char respuesta[MAX]; do { tituloPrincipal(); /* Se pide el código del producto a eliminar */ leecad(linea, MAX); /* Se verifica que el producto a buscar, exista */ if (existeProducto(codigoProducto, &producto)) { /* Se muestran los datos del producto */ leecad(respuesta, MAX); if (eliminarProducto(codigoProducto)) { } else { } } } else { /* El producto no existe */ } leecad(respuesta, MAX); repite = 0; } } while (repite); } void menuMostrar() { Producto *productos; int numeroProductos; int i; float costoTotal; float precioTotal; int cantidadTotal; char respuesta[MAX]; tituloPrincipal(); productos = obtenerProductos(&numeroProductos); /* Retorna un vector dinámico de productos */ if (numeroProductos == 0) { } else { /* Se recorre el vector dinámico de productos */ costoTotal = 0; precioTotal = 0; cantidadTotal = 0; for (i = 0; i < numeroProductos; i++) { if (productos[i].codigo != VALOR_CENTINELA) { printf("%7d \t%-20.20s%15.1f%15.1f%8d\n", productos[i].codigo, productos[i].nombre, productos[i].costo, productos[i].precio, productos[i].cantidad); costoTotal += productos[i].costo; precioTotal += productos[i].precio; cantidadTotal += productos[i].cantidad; } } leecad(respuesta, MAX); if (guardarReporte()) { } else { } } } } void menuModificar() { Producto producto; int codigoProducto; char repite = 1; char respuesta[MAX]; do { tituloPrincipal(); /* Se pide el código del producto a modificar */ leecad(linea, MAX); /* Se verifica que el producto a buscar exista */ if (existeProducto(codigoProducto, &producto)) { /* Se muestran los datos del producto */ /* Modificación del nombre del producto */ leecad(respuesta, MAX); leecad(producto.nombre, MAX); } /* Modificación del costo del producto */ leecad(respuesta, MAX); leecad(linea, MAX); } /* Modificación del precio del producto */ leecad(respuesta, MAX); leecad(linea, MAX); } /* Modificación de la cantidad del producto */ leecad(respuesta, MAX); leecad(linea, MAX); } leecad(respuesta, MAX); /* Se modifica el producto en el archivo */ if (modificarProducto(producto)) { } else { } } } else { /* El producto no existe */ } leecad(respuesta, MAX); repite = 0; } } while (repite); } void menuEliminarFisica() { char respuesta[MAX]; tituloPrincipal(); /* Se pide el código del producto a eliminar */ leecad(respuesta, MAX); if (eliminacionFisica()) { } else { } } } Producto *obtenerProductos(int *n) { FILE *archivo; Producto producto; Producto *productos; /* Vector dinámico de productos */ int i; /* Abre el archivo en modo lectura */ if (archivo == NULL) { /* Si no se pudo abrir el archivo, el valor de archivo es NULL */ *n = 0; /* No se pudo abrir. Se considera n */ productos = NULL; } else { *n = ftell(archivo) / sizeof(Producto); /* # de productos almacenados en el archivo. (# de registros) */ productos = (Producto *)malloc((*n) * sizeof(Producto)); /* Se reserva memoria para todos los productos almacenados en el archivo */ /* Se recorre el archivo secuencialmente */ i = 0; productos[i++] = producto; } /* Cierra el archivo */ } return productos; } char existeProducto(int codigoProducto, Producto *producto) { FILE *archivo; char existe; /* Abre el archivo en modo lectura */ if (archivo == NULL) { /* Si no se pudo abrir el archivo, el valor de archivo es NULL */ existe = 0; } else { existe = 0; /* Se busca el producto cuyo código coincida con codigoProducto */ if ((*producto).codigo == codigoProducto) { existe = 1; break; } } /* Cierra el archivo */ } return existe; } char insertarProducto(Producto producto) { FILE *archivo; char insercion; /* Abre el archivo para agregar datos al final */ archivo = fopen("productos.dat", "ab"); /* Añade datos al final. Si el archivo no existe, es creado */ if (archivo == NULL) { /* Si no se pudo abrir el archivo, el valor de archivo es NULL */ insercion = 0; } else { insercion = 1; /* Cierra el archivo */ } return insercion; } /* ELiminación lógica de un registro */ char eliminarProducto(int codigoProducto) { FILE *archivo; FILE *auxiliar; Producto producto; char elimina; /* Abre el archivo para leer */ archivo = fopen("productos.dat", "r+b"); /* Modo lectura/escritura. Si el archivo no existe, es creado */ if (archivo == NULL) { /* Si no se pudo abrir el archivo, el valor de archivo es NULL */ elimina = 0; } else { /* Se busca el registro que se quiere borrar. Cuando se encuentra, se sitúa en esa posición mediante la función fseek y luego se modifica el campo clave de ese registro mediante algún valor centinela, eso se logra con fwrite. Hasta allí se ha logrado una eliminación LÓGICA. Porque el registro sigue ocupando espacio en el archivo físico */ elimina = 0; if (producto.codigo == codigoProducto) { producto.codigo = VALOR_CENTINELA; elimina = 1; break; } } /* Cierra el archivo */ } return elimina; } char eliminacionFisica() { FILE *archivo; FILE *temporal; Producto producto; char elimina = 0; if (archivo == NULL || temporal == NULL) { elimina = 0; } else { /* Se copia en el archivo temporal los registros válidos */ if (producto.codigo != VALOR_CENTINELA) { } } /* Se cierran los archivos antes de borrar y renombrar */ elimina = 1; } return elimina; } char modificarProducto(Producto producto) { FILE *archivo; char modifica; Producto producto2; /* Abre el archivo para lectura/escritura */ if (archivo == NULL) { /* Si no se pudo abrir el archivo, el valor de archivo es NULL */ modifica = 0; } else { modifica = 0; if (producto2.codigo == producto.codigo) { modifica = 1; break; } } } /* Cierra el archivo */ return modifica; } char guardarReporte() { FILE *archivo; char guardado; Producto *productos; int numeroProductos; int i; float costoTotal; float precioTotal; int cantidadTotal; productos = obtenerProductos(&numeroProductos); /* Retorna un vector dinámico de productos */ if (numeroProductos == 0) { guardado = 0; } else { /* Abre el archivo en modo texto para escritura */ if (archivo == NULL) { /* Si no se pudo abrir el archivo, el valor de archivo es NULL */ guardado = 0; } else { fprintf(archivo, " ------------------------------------------------------------------------------\n"); fprintf(archivo, "%8s\t%-20s%15s%15s%10s\n", "CODIGO", "NOMBRE", "COSTO $", "PRECIO $", "CANTIDAD"); fprintf(archivo, " ------------------------------------------------------------------------------\n"); /* Se recorre el vector dinámico de productos */ costoTotal = 0; precioTotal = 0; cantidadTotal = 0; for (i = 0; i < numeroProductos; i++) { if (productos[i].codigo != VALOR_CENTINELA) { fprintf(archivo, "%7d \t%-20.20s%15.1f%15.1f%8d\n", productos[i].codigo, productos[i].nombre, productos[i].costo, productos[i].precio, productos[i].cantidad); costoTotal += productos[i].costo; precioTotal += productos[i].precio; cantidadTotal += productos[i].cantidad; } } fprintf(archivo, " ------------------------------------------------------------------------------\n"); guardado = 1; /* Cierra el archivo */ } } return guardado; } int leecad(char *cad, int n) { int i, c; /* Hay que verificar si el buffer está limpio o si hay un '\n' dejado por scanf y, en ese caso, limpiarlo: */ /* 1 COMPROBACIÓN DE DATOS INICIALES EN EL BUFFER */ /* Empezamos leyendo el primer caracter que haya en la entrada. Si es EOF, significa que no hay nada por leer, así que cerramos la cadena, dejándola "vacía" y salimos de la función retornando un valor de 0 o falso, para indicar que hubo un error */ if (c == EOF) { cad[0] = '\0'; return 0; } /* Si el valor leído es '\n', significa que había un caracter de nueva línea dejado por un scanf o función similar. Simplemente inicializamos i a 0, para indicar que los siguientes caracteres que leamos iremos asignando a partir del primer caracter de la cadena. */ if (c == '\n') { i = 0; } else { /* Si no había un '\n', significa que el caracter que leímos es el primer caracter de la cadena introducida. En este caso, lo guardamos en la posición 0 de cad, e inicializamos i a 1, porque en este caso, como ya tenemos el primer caracter de la cadena, continuaremos agregando caracteres a partir del segundo. */ cad[0] = c; i = 1; } /* 2. LECTURA DE LA CADENA */ /* El for empieza con un ; porque estamos omitiendo la inicialización del contador, ya que fue inicializado en el punto anterior. Este código lee un caracter a la vez,lo agrega a cad, y se repite hasta que se encuentre un fin de línea, fin de archivo, o haya leído la cantidad máxima de caracteres que se le indicó. Luego, cierra la cadena agregando un '\0' al final. Todo esto es muy similar a la forma en que los compiladores suelen implementar la función fgets, sólo que en lugar de getchar usan getc o fgetc */ cad[i] = c; } cad[i] = '\0'; /*3. LIMPIEZA DEL BUFFER */ /* Finalmente limpiamos el buffer si es necesario */ if (c != '\n' && c != EOF) /* es un caracter */ /* La variable c contiene el último caracter leído. Recordemos que había 3 formas de salir del for: que hayamos encontrando un '\n', un EOF, o que hayamos llegado al máximo de caracteres que debemos leer. Si se da cualquiera de los dos primeros casos, significa que leímos todo lo que había en el buffer, por lo que no hay nada que limpiar. En el tercer caso, el usuario escribió más caracteres de los debidos, que aún están en el buffer, por lo que hay que quitarlos, para lo cual usamos el método que vimos poco más arriba */ return 1; } void tituloPrincipal() { int i; i = 0; for (; i < 80; i++) { } }
MOD: Etiquetas GeSHi.