Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: Gr1nD3r en 9 Agosto 2010, 21:30 pm



Título: Duda con fread
Publicado por: Gr1nD3r en 9 Agosto 2010, 21:30 pm
Buenas. Antes que nada, el codigo:
Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. int main(){
  6. struct{
  7. char nombre[50];
  8. char direccion[100];
  9. char movil[10];
  10. char email[100];
  11. short int nDia;
  12. short int nMes;
  13. short int nAno;
  14. }persona;
  15. int i;
  16. int opcion=1; //Opcion elegida por le usuario
  17. char textoTemporal[40];
  18. FILE *fichero;
  19.  
  20. while(opcion != 0){
  21. printf("1.- A%cadir ficha nueva\n\n",164);
  22. printf("2.- Visualizar nombres de fichas existentes\n\n");
  23. printf("3.- Buscar por nombre\n\n");
  24. printf("Teclee su opcion: ");
  25. gets(textoTemporal);
  26. sscanf(textoTemporal,"%d",&opcion);
  27.  
  28. switch(opcion){
  29. case 1:
  30. fichero=fopen("gente.dat","ab");
  31. printf("Nombre: ");
  32. gets(persona.nombre);
  33. printf("Direccion: ");
  34. gets(persona.direccion);
  35. printf("Telefono movil: ");
  36. gets(persona.movil);
  37. printf("Email: ");
  38. gets(persona.email);
  39. printf("Dia de nacimiento: ");
  40. gets(textoTemporal);
  41. sscanf(textoTemporal,"%d",&persona.nDia);
  42. printf("Mes de nacimiento: ");
  43. gets(textoTemporal);
  44. sscanf(textoTemporal,"%d",&persona.nMes);
  45. printf("Año de nacimiento: ");
  46. gets(textoTemporal);
  47. sscanf(textoTemporal,"%d",&persona.nAno);
  48. fwrite(&persona,1,sizeof(persona),fichero);
  49. fclose(fichero);
  50. system("cls");
  51. break;
  52. case 2:
  53. fichero=fopen("gente.dat","rb");
  54. while(feof(fichero) == 0){
  55. fread(&persona,1,sizeof(persona),fichero);
  56. puts(persona.nombre);
  57. }
  58. fclose(fichero);
  59. break;
  60.  
  61. case 3:
  62. printf("Introduzca el nombre de la persona: ");
  63. gets(textoTemporal);
  64. fichero=fopen("gente.dat","rb");
  65. fread(persona.nombre,1,sizeof(persona.nombre),fichero);
  66. fread(persona.direccion,1,sizeof(persona.direccion),fichero);
  67. fread(persona.movil,1,sizeof(persona.movil),fichero);
  68. fread(persona.email,1,sizeof(persona.email),fichero);
  69. fread(&persona.nDia,sizeof(persona.nDia),1,fichero);
  70. fread(&persona.nMes,sizeof(persona.nMes),1,fichero);
  71. fread(&persona.nAno,sizeof(persona.nAno),1,fichero);
  72. if((strcmp(persona.nombre,textoTemporal)== 0)){
  73. printf("Nombre: ");
  74. puts(persona.nombre);
  75. printf("Direccion: ");
  76. puts(persona.direccion);
  77. printf("Movil: ");
  78. puts(persona.movil);
  79. printf("email: \n");
  80. puts(persona.email);
  81. printf("Dia de nacimiento: %d\n",persona.nDia);
  82. printf("Mes de nacimiento: %d\n",persona.nMes);
  83. printf("A%co de nacimiento: %d\n",164,persona.nAno);
  84. }
  85. fclose(fichero);
  86. }3
  87. }
  88. return 0;
  89. }
  90.  
El problema es el siguiente: Cuando escojo la opcion 2, se deben mostrar todos los nombres de las fichas guardadas. Pero el ultimo nombre siempre se repite y se imprime en pantalla dos veces. Alguien sane a que se debe????
pd: La opcion 3 no esta mal, aun no la he modificado
GRACIAS!!


Título: Re: Duda con fread
Publicado por: Littlehorse en 10 Agosto 2010, 21:24 pm
Lo primero es que no utilices gets, es peligrosa y logra que tu programa sea propenso a errores, desbordamiento de buffer, etc. Utiliza fgets.

En cuanto al error, no he visto todo el código pero viendo la parte relevante a la pregunta en cuestión:

Código
  1. while(feof(fichero) == 0)
  2. {
  3. fread(&persona,1,sizeof(persona),fichero);
  4. puts(persona.nombre);
  5. }

El error es sencillo, nunca debes utilizar feof de esa forma para comprobar el final de un archivo en un ciclo. feof devuelve verdadero después de pasar EOF, no al alcanzarlo.

Lo que sucede respectivamente es que fread lee el ultimo dato, pero no el final del archivo. Entonces al intentar leer nuevamente, se produce un error, y lo que haya quedado en el buffer se vuelve a imprimir porque la condición del ciclo, según feof, todavía no se ha cumplido.

No te pongo la función porque es fácil de solucionar y creo que va a ser mas productivo que la hagas vos mismo, pero como pista te digo que puedes valerte de una combinación de feof y el valor de retorno de fread, o bien solamente de este ultimo.

Recordando que el valor de retorno de fread implica:

Citar
Return Value
The total number of elements successfully read is returned as a size_t object, which is an integral data type.
If this number differs from the count parameter, either an error occured or the End Of File was reached.
You can use either ferror or feof to check whether an error happened or the End-of-File was reached.

Saludos