Problema en C con la funcion fread y fwrite

Iniciado por M01535, 26 Marzo 2015, 15:57 PM

0 Miembros y 3 Visitantes están viendo este tema.

M01535

Buenas, estoy haciendo un ejercicio de programacion en C en el cual tengo que lograr lo siguiente: Crear un "struct" que almacene los siguientes datos de una persona: nombre, edad, ciudad de residencia. Pedir al usuario esos datos de una persona y guardarlos en un fichero llamado "gente1.dat", usando "fwrite". Cerrar el fichero, volverlo a abrir para lectura y mostrar los datos que se habían guardado, que se deben leer con "fread".

Aun me cuesta entender como funciona exactamente la orden fread y fwrite, por ejemplo, escribiendo: fread(&ficha, sizeof(ficha), 1, fichero); &ficha se refiere al lugar donde se guardan los datos, sizeof(ficha) el tamaño de los datos, el 1 a la cantidad de datos a leer, pero ¿hasta donde se lee?, ¿hasta que encuentre un \0 o \n?, no entiendo muy bien ese 1.

Bueno, aqui os dejo mi intento del ejercicio anterior, el cual casi al finalizar me tira "programa.exe has stopped working" y no se donde está el error.
Edit: Aclarar que el programa me da dos warning: "assignment make pointer from integer without a cast"
#include <stdio.h>
#include <string.h>

int main(){

struct{
char Name[100],City[100];
int Age;
}Persona;
FILE *Gente1;
int X;

if(Gente1=fopen("gente1.dat","ab")==NULL){
   printf("No se puede escribir en el fichero...\n");
}
else{
   printf("Que nombre deseas introducir?: ");
   fflush(stdin);
   gets(Persona.Name);
   printf("\nCiudad?: ");
   fflush(stdin);
   gets(Persona.City);
   printf("\nEdad?: ");
   fflush(stdin);
   scanf("%d",&Persona.Age);
   fwrite(&Persona,sizeof(Persona),1,Gente1);
   fclose(Gente1);
}

if(Gente1=fopen("gente1.dat","rb")==NULL){
   printf("\nNo se puede leer el fichero...\n");
}
else{
   while(!feof(Gente1)){
       fread(&Persona,sizeof(Persona),1,Gente1);
       puts(Persona.Name);
       puts(Persona.City);
       printf("%s\n",Persona.Age);
   }
   fclose(Gente1);
}

fflush(stdin);
getchar();
return 0;
}


Muchas gracias de antemano!

ivancea96

Estas escribiendo y leyendo datos binarios. No se atiende ni a caracteres nulos ni a saltos de linea. Si tu le especificas leer X bytes, leerá X bytes, no más.

La cantidad de bytes que leerá fread en total, será el tamaño del tipo o estructura que le pasas (segundo parámetro), multiplicado por el número de elementos del arreglo (tercer parámetro.

fwrite es más de lo mismo.

Si quieres información detallada de las funciones, http://www.cplusplus.com/reference/cstdio/fread/.

M01535

Muchas gracias ivancea96 por tu respuesta, eso de la cantidad de bytes que leerá fread en total me ha quedado bastante claro ;-) Ahora bien, alguien tiene idea de por qué el programa me tira los warning: "assignment make pointer from integer without a cast" y al ejecutarlo, cuando va a finalizar el programa, deja de funcionar: "program.exe has stopped working"

rir3760

Cita de: M01535 en 26 Marzo 2015, 17:08 PMalguien tiene idea de por qué el programa me tira los warning: "assignment make pointer from integer without a cast" y al ejecutarlo, cuando va a finalizar el programa, deja de funcionar: "program.exe has stopped working"
Los errores se generan en las llamadas a fopen:
if (Gente1 = fopen("gente1.dat","ab") == NULL){

/* ... */

if (Gente1 = fopen("gente1.dat","rb") == NULL){

El operador "==" tiene una prioridad mayor que "=" por lo que esas sentencias se procesan así:
if (Gente1 = (fopen("gente1.dat","ab") == NULL)){

/* ... */

if (Gente1 = (fopen("gente1.dat","rb") == NULL)){

Por ello la variable almacenara el valor entero cero si fopen tiene éxito y uno en caso contrario.

Para solucionarlo solo tienes que utilizar paréntesis para primero asignar y solo entonces comparar:
if ((Gente1 = fopen("gente1.dat","ab")) == NULL){

/* ... */

if ((Gente1 = fopen("gente1.dat","rb")) == NULL){


Por ultimo evita el uso de gets y fflush(stdin), las razones de ello en el tema |Lo que no hay que hacer en C/C++. Nivel basico|

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

M01535

Muchas gracias por tu respuesta rir3760, me habeis ayudado bastante y he aprendido unas cuantas cosas nuevas, lo agradezo. He hecho unas "mejoras" al programa también teniendo en cuenta lo que me comentaste de fflush(stdin) y los gets, aqui tengo el nuevo codigo a ver que os parece
#include <stdio.h>
#include <string.h>

int main(){

struct{
char Name[100],City[100];
int Age;
}Persona;
FILE *Gente1;
int X;
char Buffer[200];

if((Gente1=fopen("gente1.dat","wb"))==NULL){
    printf("No se puede escribir en el fichero...\n");
}
else{
    printf("Que nombre deseas introducir?: ");
    fgets(Persona.Name,sizeof(Persona.Name),stdin);
    printf("\nCiudad?: ");
    fgets(Persona.City,sizeof(Persona.City),stdin);
    printf("\nEdad?: ");
    fgets(Buffer,sizeof(Buffer),stdin);
    sscanf(Buffer,"%d",&Persona.Age);
    fwrite(&Persona,sizeof(Persona),1,Gente1);
    fclose(Gente1);
}

if((Gente1=fopen("gente1.dat","rb"))==NULL){
    printf("\nNo se puede leer el fichero...\n");
}
else{
    while(!feof(Gente1)){
        fread(&Persona,sizeof(Persona),1,Gente1);
        if(strlen(Persona.Name)>0) Persona.Name[strlen(Persona.Name)-1]='\0';
        if(!feof(Gente1)) puts(Persona.Name);
        if(strlen(Persona.City)>0) Persona.City[strlen(Persona.City)-1]='\0';
        if(!feof(Gente1)) puts(Persona.City);
        if(!feof(Gente1)) printf("%d\n",Persona.Age);
    }
}
fclose(Gente1);

return 0;
}

rir3760

Para imprimir el registro almacenado en el archivo no necesitas de un bucle, en su lugar basta con una sentencia condicional donde se verifique el valor de retorno de la función (uno en caso de una lectura exitosa). De esta forma:
if (fread(&Persona, sizeof(Persona), 1, Gente1) == 1)
   printf("%s%s%d\n", Persona.Name, Persona.City, Persona.Age);


Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

M01535

Gracias a todos por vuestras respuestas, son de gran ayuda. Bueno, me surgió una nueva duda sobre fread y fwrite (la guerra que me está dando esta orden... :xD) asi que aprovecho este mismo tema para exponerla.
El programa a construir es el siguiente: Mejorar la agenda anterior (del apartado 6.4), para guardar y leer cada "ficha" (struct) de una vez, usando fwrite/fread y sizeof, como en el último ejemplo.
Y aqui teneis el código de la agenda de la que se habla:
#include <stdio.h>
#include <string.h>

int main(){

FILE* Agenda;
struct{
    char Name[100],Adress[100],Email[100],Movil[13];
    unsigned short int Day,Month,Year;
}Datos[100];
char Buffer[200],Buscar[200];
int X=0,Y,Menu,Algodon=0;

//LEER DATOS DEL FICHERO
Agenda=fopen("agenda.dat","rt");
while(!feof(Agenda)){
    fgets(Buffer,200,Agenda);
    if(feof(Agenda)) break;
    if(strlen(Buffer)>0) Buffer[strlen(Buffer)-1]='\0';
    strcpy(Datos[X].Name,Buffer);

    fgets(Buffer,200,Agenda);
    if(feof(Agenda)) break;
    if(strlen(Buffer)>0) Buffer[strlen(Buffer)-1]='\0';
    strcpy(Datos[X].Adress,Buffer);

    fgets(Buffer,200,Agenda);
    if(feof(Agenda)) break;
    if(strlen(Buffer)>0) Buffer[strlen(Buffer)-1]='\0';
    strcpy(Datos[X].Movil,Buffer);

    fgets(Buffer,200,Agenda);
    if(feof(Agenda)) break;
    if(strlen(Buffer)>0) Buffer[strlen(Buffer)-1]='\0';
    strcpy(Datos[X].Email,Buffer);

    fgets(Buffer,200,Agenda);
    if(feof(Agenda)) break;
    sscanf(Buffer,"%d",&Datos[X].Day);

    fgets(Buffer,200,Agenda);
    if(feof(Agenda)) break;
    sscanf(Buffer,"%d",&Datos[X].Month);

    fgets(Buffer,200,Agenda);
    if(feof(Agenda)) break;
    sscanf(Buffer,"%d",&Datos[X].Year);
    Algodon=1;
    X++;
}
fclose(Agenda);
if(Algodon==0){
    printf("No hay datos que leer...\n\n");
}
else if(Algodon==1){
    printf("Datos leidos...\n\n");
}

do{
    printf("1 - Introducir nuevo dato\n2 - Ver todos los nombres de los datos\n3 - Buscar\n0 - Salir\nQue desea hacer?: ");
    fgets(Buffer,sizeof(Buffer),stdin);
    sscanf(Buffer,"%d",&Menu);

    switch(Menu){
    //INGRESAR NUEVO DATO
    case 1:
    printf("\n\nNUEVO DATO:\nIngrese el nombre: ");
    fgets(Datos[X].Name,sizeof(Datos[X].Name),stdin);
    Datos[X].Name[strlen(Datos[X].Name)-1]='\0';

    printf("Ingrese la ciudad: ");
    fgets(Datos[X].Adress,sizeof(Datos[X].Adress),stdin);
    Datos[X].Adress[strlen(Datos[X].Adress)-1]='\0';

    printf("Ingrese el numero de movil: ");
    fgets(Datos[X].Movil,sizeof(Datos[X].Movil),stdin);
    Datos[X].Movil[strlen(Datos[X].Movil)-1]='\0';

    printf("Ingrese el email: ");
    fgets(Datos[X].Email,sizeof(Datos[X].Email),stdin);
    Datos[X].Email[strlen(Datos[X].Email)-1]='\0';

    printf("Ingrese el dia de nacimiento: ");
    fgets(Buffer,sizeof(Buffer),stdin);
    sscanf(Buffer,"%d",&Datos[X].Day);

    printf("Ingrese el mes de nacimiento: ");
    fgets(Buffer,sizeof(Buffer),stdin);
    sscanf(Buffer,"%d",&Datos[X].Month);

    printf("Ingrese su year de nacimiento: ");
    fgets(Buffer,sizeof(Buffer),stdin);
    sscanf(Buffer,"%d",&Datos[X].Year);
    X++;
    break;

    //MOSTRAR LOS NOMBRES DE TODOS LOS DATOS
    case 2:
        if(X==0){
            printf("\n\nNo hay datos que mostrar\n\n");
            break;
        }

    printf("\n\nEstos son los nombres de todos los datos:\n");
    for(Y=0;Y<X;Y++){
        printf("%d - %s\n",Y,Datos[Y].Name);
    }
    printf("\n");
        break;

    //BUSCAR DATO POR NOMBRE
    case 3:
        printf("\n\nIntroduzca el nombre del contacto que desea buscar: ");
        fgets(Buscar,sizeof(Buscar),stdin);
        Buscar[strlen(Buscar)-1]='\0';
        Algodon=0;

        for(Y=0;Y<X;Y++){
            if(strcmp(Buscar,Datos[Y].Name)==0){
                printf("\nSe ha encontrado este/os resultado/s:\n");
                printf("Name: %s\nAdress: %s\nPhone: %s\nEmail: %s\nBorn in: %d-%d-%d\n\n",Datos[Y].Name,Datos[Y].Adress,Datos[Y].Movil,Datos[Y].Email,Datos[Y].Day,Datos[Y].Month,Datos[Y].Year);
                Algodon=1;
            }
        }
        if(Algodon==0){
            printf("\nNo se han encontrado resultados...\n\n");
        }
    }
}while(Menu!=0);

//ESCRIBIR LOS DATOS EN EL FICHERO
Agenda=fopen("agenda.dat","wt");
for(Y=0;Y<X;Y++){
    fprintf(Agenda,"%s\n",Datos[Y].Name);
    fprintf(Agenda,"%s\n",Datos[Y].Adress);
    fprintf(Agenda,"%s\n",Datos[Y].Movil);
    fprintf(Agenda,"%s\n",Datos[Y].Email);
    fprintf(Agenda,"%d\n",Datos[Y].Day);
    fprintf(Agenda,"%d\n",Datos[Y].Month);
    fprintf(Agenda,"%d\n",Datos[Y].Year);
}
fclose(Agenda);

printf("\nSaliendo...");

return 0;
}


Bueno, para facilitar las cosas, las partes donde hay que sustituir e introducir un fread y fwrite son las siguientes:

fread
Agenda=fopen("agenda.dat","rt");
while(!feof(Agenda)){
    fgets(Buffer,200,Agenda);
    if(feof(Agenda)) break;
    if(strlen(Buffer)>0) Buffer[strlen(Buffer)-1]='\0';
    strcpy(Datos[X].Name,Buffer);

    fgets(Buffer,200,Agenda);
    if(feof(Agenda)) break;
    if(strlen(Buffer)>0) Buffer[strlen(Buffer)-1]='\0';
    strcpy(Datos[X].Adress,Buffer);

    fgets(Buffer,200,Agenda);
    if(feof(Agenda)) break;
    if(strlen(Buffer)>0) Buffer[strlen(Buffer)-1]='\0';
    strcpy(Datos[X].Movil,Buffer);

    fgets(Buffer,200,Agenda);
    if(feof(Agenda)) break;
    if(strlen(Buffer)>0) Buffer[strlen(Buffer)-1]='\0';
    strcpy(Datos[X].Email,Buffer);

    fgets(Buffer,200,Agenda);
    if(feof(Agenda)) break;
    sscanf(Buffer,"%d",&Datos[X].Day);

    fgets(Buffer,200,Agenda);
    if(feof(Agenda)) break;
    sscanf(Buffer,"%d",&Datos[X].Month);

    fgets(Buffer,200,Agenda);
    if(feof(Agenda)) break;
    sscanf(Buffer,"%d",&Datos[X].Year);
    Algodon=1;
    X++;
}
fclose(Agenda);


fwrite
Agenda=fopen("agenda.dat","wt");
for(Y=0;Y<X;Y++){
    fprintf(Agenda,"%s\n",Datos[Y].Name);
    fprintf(Agenda,"%s\n",Datos[Y].Adress);
    fprintf(Agenda,"%s\n",Datos[Y].Movil);
    fprintf(Agenda,"%s\n",Datos[Y].Email);
    fprintf(Agenda,"%d\n",Datos[Y].Day);
    fprintf(Agenda,"%d\n",Datos[Y].Month);
    fprintf(Agenda,"%d\n",Datos[Y].Year);
}
fclose(Agenda);


Muchas gracias por vuestra atención y un saludo. :D

rir3760

La recomendación anterior se mantiene: no utilices feof, en su lugar verifica el valor de retorno de la función en turno. También utiliza nombres descriptivos para las variables, "algodon" no lo es.

----

El bucle de lectura lo puedes sustituir con una sola llamada a fread:
int num_regs; /* Numero de registros */

/* ... */

// Leer datos del fichero
Agenda = fopen("agenda.dat", "rb");
num_regs = fread(Datos, sizeof Datos[0], 100, Agenda);
fclose(Agenda);

Con ella se le indica a la función que lea un máximo de 100 registros del archivo y los almacene a partir de la dirección indicada por "Agenda". El numero actual de registros leídos se almacena en la variable "num_regs".

En la misma linea el bucle de escritura se sustituye por la llamada a función:
// Escribir los datos en el fichero
Agenda = fopen("agenda.dat", "wb");
fwrite(Datos, sizeof Datos[0], num_regs, Agenda);
fclose(Agenda);


----

Ya por ultimo cuando se desea leer un valor de tipo unsigned short el especificador de formato con scanf y familia es "%hu".

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language