estructuras y lectura de archivos en C

Iniciado por michellcrh, 30 Mayo 2020, 06:25 AM

0 Miembros y 1 Visitante están viendo este tema.

michellcrh

 :-\Hola tengo que realizar un programa haciendo uso de estructuras dinamicas y lectura de archivos, pero no puedo hacer correctamente la extracción de los archivos y guardarlos en arreglos.
Solo guarda el nombre y la cantidad, pero el autor y el precio no.

Este es mi código:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct{
   char *nombre;
   char *autor;
   int cantidad;
   int precio;
}libros;
libros *l;

void menu();
void vaciar(char temp[]);
void copiarNombre(char temp[],int i);
void copiarAutor(char temp[],int i);

int main(){
   char temp[50],aux;
   int contador = 0;

   FILE *fichero;
   fichero = fopen("libros.txt","rt");
   if(fichero == NULL){
       printf("No se ha encontrado el documento\n");
       return 0;
   }
   while(!feof(fichero)){
       fgets(temp,50,fichero);
       contador++;
   }
   rewind(fichero);
   l = (libros*)malloc(contador*sizeof(libros));
   if(l == NULL){
       printf("NO SE HA PODIDO RESERVAR LA MEMORIA\n");
       return 0;
   }
   for(int i=0;!feof(fichero); i++){
       vaciar(temp);
       aux = '0';
       for(int j=0; aux != ','; j++ ){
               aux = fgetc(fichero);
               if(aux != ','){
                   temp[j] = aux;
               }
       }
       copiarNombre(temp,i);
       copiarAutor(temp,i);
       fgets(temp,4,fichero);
       l[i].cantidad = atoi(temp);
       fgets(temp,5,fichero);
       l[i].precio = atoi(temp);
      printf("Precio: %d\n",l[i].precio);

   }
   fclose(fichero);

   getchar();
   return 0;
}

void menu(){
   int opc;

   printf("\t\t\tLIBRERIA FI\n\n");
   printf("1. Leer inventario inicial\n");
   printf("2. Mostrar inventario de existencias\n");
   printf("3. Vender libros\n");
   printf("4. Informe de ventas\n");
   printf("5. Salir\n");
   printf(" \nIngrese el numero correspondiente a la operacion que desea realizar: ");
   scanf("%d",&opc);
}

void vaciar(char temp[]){
   for(int i=0; i<50; i++){
       temp[i] = '\0';
   }
}

void copiarNombre(char temp[],int i){
   int longitud;
   longitud = strlen(temp)+1;
   l[i].nombre = (char*)malloc(longitud*sizeof(char));
   if(l[i].nombre == NULL){
       printf("No se ha podido reservar memoria\n");
       return 0;
   }
   strcpy(l[i].nombre,temp);
}

void copiarAutor(char temp[],int i){
   int longitud;
   longitud = strlen(temp)+1;
   l[i].autor = (char*)malloc(longitud*sizeof(char));
   if(l[i].autor == NULL){
       printf("No se ha podido reservar memoria\n");
       return 0;
   }
   strcpy(l[i].autor,temp);
}



mi archivo de texto es el siguiente:

La casa de los espiritus,Isabel Allende,5,345
La Metamorfosis,Franz Kafka,3,560
La Odisea,Homero,7,200
El Principito,Antoine de Saint-Exupery,2,499
El Laberinto de la Soledad,Octavio Paz,1,150
El tunel,Ernesto Sabato,3,100
Los miserables,Victor Hugo,5,290
Cuentos de amor de locura y de muerte,Horacio Quiroga,4,563
El amor en lo tiempos de colera,Gabriel Garcia Marquez,6,218




MOD: Utiliza las etiquetas de Código GeSHi para los fragmentos de código

K-YreX

El problema principal es la separación que estás haciendo en tokens o partes.
Buscas hasta la primera coma (,) para localizar el nombre del libro pero de seguido guardas el nombre del autor también sin haber buscado hasta la siguiente coma. Por lo tanto, el nombre del libro y el autor siempre son la misma cadena.
A partir de ahí ya se descuadran todos los cálculos (que tampoco entiendo esos fgets() con longitud 4 y 5...) y se guarda todo mal.

Además otro problema es que la cadena que usas para guardar cada línea del fichero temporalmente tiene una longitud de 50 y hay líneas que superan ese número de caracteres por lo que los caracteres que no entran en una línea, se leen en la siguiente.

Otro otro tema importante cuando se trabaja con memoria dinámica es que esa memoria tienes que liberarla manualmente usando free().

Y otro tema es usar return para salir en caso de error. En la función main() se puede hacer porque de un return acaba el programa pero en otras funciones auxiliares, llamar a return lo que hace es devolver el control a la función que llamó a esta. Es más correcto utilizar exit().
Además el valor 0 se suele asociar a que todo ha finalizado correctamente. Para errores es mejor usar -1. En conjunto: exit(-1).

Otros consejos son:
  • Utilizar una constante para la longitud de la cadena que te permita modificarlo rápidamente sin tener que ir mirando por todo el código.
  • No utilizar variables globales, como en tu caso el puntero l.
  • Para separar una cadena en base a un patrón o varios tienes la función strtok().
  • Para "vaciar" una cadena no es necesario poner '\0' a todas sus posiciones. Basta con hacerlo en la posición 0.

    Te dejo otra forma de hacerlo con las modificaciones antes mencionadas:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    #define SIZE 100

    typedef struct {
    char *nombre;
    char *autor;
    int cantidad;
    int precio;
    } Libro;


    void liberarMemoria(Libro *libros, int numeroLibros){
    for(int i = 0; i < numeroLibros; ++i){
    free(libros[i].nombre);
    free(libros[i].autor);
    }
    free(libros);
    }

    void guardarLibro(Libro *libros, char *temporal, int numeroLibros){
    char *token = strtok(temporal, ",");
    libros[numeroLibros-1].nombre = (char*)malloc((strlen(token)+1) * sizeof(char));
    strcpy(libros[numeroLibros-1].nombre, token);

    token = strtok(NULL, ",");
    libros[numeroLibros-1].autor = (char*)malloc((strlen(token)+1) * sizeof(char));
    strcpy(libros[numeroLibros-1].autor, token);

    token = strtok(NULL, ",");
    libros[numeroLibros-1].cantidad = atoi(token);

    token = strtok(NULL, ",");
    libros[numeroLibros-1].precio = atoi(token);
    }

    void mostrarLibros(Libro *libros, int numeroLibros){
    for(int i = 0; i < numeroLibros; ++i){
    printf("***** INFORMACION LIBRO %d *****\n", i+1);
    printf("Nombre: %s\n", libros[i].nombre);
    printf("Autor: %s\n", libros[i].autor);
    printf("Cantidad: %d\n", libros[i].cantidad);
    printf("Precio: %d\n", libros[i].precio);
    printf("\n");
    }
    }

    int main(){
    Libro *libros = NULL;
    char temporal[SIZE];
    FILE *fichero = fopen("libros.txt", "r");

    int numeroLibros = 0;
    while(fgets(temporal, SIZE, fichero)) {
    ++numeroLibros;
    libros = (Libro*)realloc(libros, numeroLibros * sizeof(Libro));
    guardarLibro(libros, temporal, numeroLibros);
    }

    mostrarLibros(libros, numeroLibros);

    liberarMemoria(libros, numeroLibros);
    return 0;
    }


    PD: Cuando vayas a insertar código utiliza etiquetas de Código GeSHi y selecciona el lenguaje que corresponda a tu código. En tu mensaje anterior ya te las he incluido yo pero para otra ocasión.

    PD 2: Aunque no es relevante, el menú que tienes no funciona. Si vas a pedir una opción tendrás que devolverla con un return.
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

michellcrh