[ Foro de C ]

Ejercicio 6.4.2

06-Mar-2014 17:41
Jaime Daviu
2 Respuestas

Hola a todos,
       Tengo un problema con los ejercicios  6.4.2 en la parte de lectura desde archivo.
Resulta que cuando abro el archivo creado desde un editor de texto convencional todo aparece como espero; pero a leer con el programa que yo escribo me lee siempre mal.
He visto las soluciones que dan Nacho y  otro chico, pero algo me falla.

Os pongo aqui mi codigo del ejercicio 6.4.2:


/* Ejercicio Cabanes 6.4.2.8 */
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int main()
{
    FILE* fichero;
    char nombre[80] = "gente9.dat"; 
    char linea0[11], linea1[81];
    struct
    {
        char nom[31];  /* Nombre de la persona*/
        char edad[6];
        char lugar[41];  /* Lugar de residencia */
    } persona[5];  /* Lo intento con 5 para hacer las pruebas mas rapido */
    int i, nPersona;
    for (i=0; i<5; i++)
    {
        printf("Escriba el nombre de una persona: \n");
        fgets(persona[i].nom, 30, stdin);
        printf("Escriba la edad de la persona: \n");
        fgets(persona[i].edad, 5, stdin);
        printf("Escriba el lugar de residencia de la persona: \n");
        fgets(persona[i].lugar, 40, stdin);
    }
    fichero = fopen(nombre, "wt");
    if (fichero == NULL)
    {
        printf("El fichero no existe. \n");
        exit(1);
    }
    for (i=0; i<5; i++)
    {
        fprintf(fichero, "%30s", persona[i].nom);
        fprintf(fichero, "%5s", persona[i].edad);
        fprintf(fichero, "%40s", persona[i].lugar);
    }
    fclose(fichero);

    do
    {
        printf("Escriba un numero de persona y le dare sus datos: \n");
        fgets(linea0, 10, stdin);
        sscanf(linea0, "%d", &nPersona);
        if ((nPersona < 5) && (nPersona > -1))
        {
            fichero = fopen(nombre, "rt");
            if (fichero == NULL)
            {
                printf("El fichero no existe");
                exit(1);
            }
            for(i=0; i<nPersona; i++)
            {
                fgets(linea1, 30, fichero);
                if ((strlen(linea1) > 0) && (linea1[strlen(linea1) -1] == '\n'))
                    linea1[strlen(linea1) -1] = '\0';
                fgets(linea1, 5, fichero);
                if ((strlen(linea1) > 0) && (linea1[strlen(linea1) -1] == '\n'))
                    linea1[strlen(linea1) -1] = '\0';
                fgets(linea1, 40, fichero);
                if ((strlen(linea1) > 0) && (linea1[strlen(linea1) -1] == '\n'))
                    linea1[strlen(linea1) -1] = '\0';
            }
            i++;
            fgets(linea1, 30, fichero);
            if ((strlen(linea1) > 0) && (linea1[strlen(linea1) -1] == '\n'))
                linea1[strlen(linea1) -1] = '\0';
            puts(linea1);
            fgets(linea1, 5, fichero);
            if ((strlen(linea1) > 0) && (linea1[strlen(linea1) -1] == '\n'))
                linea1[strlen(linea1) -1] = '\0';
            puts(linea1);
            fgets(linea1, 40, fichero);
            if ((strlen(linea1) > 0) && (linea1[strlen(linea1) -1] == '\n'))
                linea1[strlen(linea1) -1] = '\0';
            puts(linea1);
        }
        else
            break;
        fclose(fichero);
    }
    while ((nPersona < 5) && (nPersona > -1));
    return 0;
}



08-Mar-2014 12:44
Nacho Cabanes (+83)

La apariencia es muy buena. Tendría que saber más detalles sobre qué está fallando. En principio, el riesgo podría estar en casos muy concretos, cuando haces


fgets(linea1, 30, fichero);


Porque si esa línea ocupa justo 30 bytes, dejarías el avance de línea en el fichero, y eso sería lo que leerías en la siguiente lectura (y que se interpretaría como un dato vacío).

No me queda muy claro lo que pretendes con el


if ((strlen(linea1) > 0) && (linea1[strlen(linea1) -1] == '\n'))
                    linea1[strlen(linea1) -1] = '\0';


Lo veo innecesariamente rebuscado, porque "fgets" siempre va a incluir el "\n" al final de la cadena (salvo si no llegas hasta el final de línea, caso en el que posiblemente estarás analizando mal el fichero, y dejando datos incorrectos para la siguiente lectura).

Reduce el problema a un fichero de datos lo más pequeño posible y ponlo aquí, por si ayuda a ver mejor el problema.


12-Mar-2014 00:18
Jaime Daviu

       ¡Muchas gracias Nacho! Tenías razón con lo de la longitud de linea de 30 bytes.
Lo he hecho añadiendo 1 mas en la lectura (de 30 a 31, de 5 a 6 y de 40 a 41) y ahora me sale bien.
(Antes me hacia dos cosas mal: me daba solo dos datos y de una persona incorrecta).

Escritura:


...
  for (i=0; i<5; i++)
    {
        printf("Escriba el nombre de una persona: \n");
        fgets(persona[i].nom, 30, stdin);
        printf("Escriba la edad de la persona: \n");
        fgets(persona[i].edad, 5, stdin);
        printf("Escriba el lugar de residencia de la persona: \n");
        fgets(persona[i].lugar, 40, stdin);
    }
...


Lectura


...
            fgets(linea1, 31, fichero);
            puts(linea1);
            fgets(linea1, 6, fichero);
            puts(linea1);
            fgets(linea1, 41, fichero);
            puts(linea1);
        }
...


Y lo que pretendía con lo de:


         if ((strlen(linea1) > 0) && (linea1[strlen(linea1) -1] == '\n'))
                linea1[strlen(linea1) -1] = '\0';


era escribir "a prueba de fallos", pues llevaba varias horas y no me salía. Así que me inspiré en los consejos que creo que das en el capitulo 6.14 de la version 0.95, pagina 130. (Aunque quizá lo saqué de contexto).






(No se puede continuar esta discusión porque tiene más de dos meses de antigüedad. Si tienes dudas parecidas, abre un nuevo hilo.)