• Sábado 9 de Noviembre de 2024, 02:22

Autor Tema:  [C] Estructuras y archivos binarios  (Leído 12105 veces)

Amphoth3ra

  • Nuevo Miembro
  • *
  • Mensajes: 7
    • Ver Perfil
[C] Estructuras y archivos binarios
« en: Domingo 8 de Mayo de 2011, 21:11 »
0
Los problemas que yo tengo se relaciona con estructuras y con el guardado de estas estructuras y archivos binarios. Les explico el concepto: Lo que estoy buscando es almacenar una serie de parámetros a una estructura (rut, edad y nombre) y luego esta estructura se pasa a un archivo binario, el cual luego yo debo leerlo por atributo (sea rut, nombre o edad).

A mí me ocurren dos problemas con el programa que estoy haciendo. En primera instancia, el rut que yo introduzco inicialmente se introduce bien, pero cuando yo lo rescato del archivo binario la parte del rut me aparece con un caracter más del que yo puse originalmente, vale decir que si yo introduzco esta información:

Rut              Edad   Nombre
--------------------------------------------------------------------
12.346.812-7     52     Stephen Berger


Del archivo se me regresa lo siguiente:

Rut              Edad   Nombre
--------------------------------------------------------------------
12.346.812-74     52     Stephen Berger
 

Lo otro extraño que me pasa es que la última estructura que pongo se me duplica al rescatar la información del archivo binario, vale decir, si yo pongo esta información:
Rut              Edad   Nombre
--------------------------------------------------------------------
12.222.618-7     54     Jorge Contreras
12.228.164-4     59     Gerónimo Vallejos
13.433.618-K     47     Claudia Cotapos


Del archivo se me regresa esto:
Rut              Edad   Nombre
--------------------------------------------------------------------
12.222.618-76     54     Jorge Contreras
12.228.164-4;     59     Gerónimo Vallejos
13.433.618-K/     47     Claudia Cotapos
13.433.618-K/     47     Claudia Cotapos

 
Nótese que en lo anterior también se me repite el problema del rut, ustedes pueden ver que me sale un caracter adicional al rut.

Este es el código del programa:
Código: C
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. struct persona {
  6.  char rut[12];
  7.  int edad;
  8.  char nombre[255];
  9.  };
  10.  
  11. // Declaración de tabla y creación del archivo con el que se vá a trabajar
  12. void create_table_personas()
  13. {
  14.     FILE *principal_file, *test_file;
  15.  
  16.     principal_file = fopen ("archivo.dat", "wb");
  17.     if (principal_file==NULL)
  18.         printf ("No se pudo crear el archivon");
  19.  
  20.     fclose(principal_file);
  21.  
  22.     test_file = fopen ("archivo.dat", "rb");
  23.     if (test_file==NULL)
  24.         printf ("No se pudo abrir el archivon");
  25.     rewind(test_file);
  26. }
  27.  
  28. // Inserción en la tabla
  29. void insert_into_table()
  30. {
  31.     int menu2_on = 1;
  32.  
  33.     struct persona avance;
  34.  
  35.     FILE *save_file;
  36.  
  37.     save_file = fopen ("archivo.dat", "r+wb");
  38.  
  39.     fread (&avance, sizeof(struct persona), 1, save_file);
  40.  
  41.     if (avance.edad == 0)
  42.         rewind(save_file);
  43.  
  44.     do {
  45.         do {
  46.             fread (&avance, sizeof(struct persona), 1, save_file);
  47.         } while (!feof(save_file)); 
  48.  
  49.         struct persona data_save;
  50.  
  51.         printf("Rut de la personan");
  52.         scanf("%*c%[^n]",data_save.rut);
  53.         printf("Edad de la personan");
  54.         scanf("%d", &data_save.edad);
  55.         printf("Nombre de la personan");
  56.         scanf("%*c%[^n]",data_save.nombre);
  57.        
  58.         fwrite (&data_save , 1 , sizeof(struct persona) , save_file);
  59.  
  60.         printf("¿Desea agregar otra tupla? (1 Si, 0 No)n");
  61.         scanf("%d", &menu2_on);
  62.  
  63.     } while (menu2_on == 1);
  64.  
  65.     fclose(save_file);
  66.  
  67.     struct persona junior;
  68.     FILE  *test_file;
  69.    
  70.     test_file = fopen ("archivo.dat", "rb");
  71.     if (test_file==NULL)
  72.         printf ("No se pudo abrir el archivon");
  73.  
  74.     printf("Rut              Edad   Nombren");
  75.     printf("--------------------------------------------------------------------n");   
  76.     while (!feof(test_file))
  77.     {   
  78.         fread (&junior, sizeof(struct persona), 1, test_file);
  79.  
  80.         printf("%s     %d     %sn", junior.rut, junior.edad, junior.nombre);  
  81.  
  82.     }
  83. }
  84.  
  85. // Función: Consulta por edad //
  86. void attribute_age()
  87. {
  88.     FILE *checker;
  89.  
  90.     struct persona temporal;
  91.  
  92.     int edad_consulta;
  93.  
  94.     printf("Inserte la edad a consultarn");
  95.     scanf("%d",&edad_consulta);
  96.  
  97.     checker = fopen ("archivo.dat", "rb");
  98.     if (checker==NULL)
  99.         printf ("No se pudo abrir el archivon");
  100.     rewind(checker);
  101.    
  102.     printf("Rut              Edad   Nombren");
  103.     printf("--------------------------------------------------------------------n");
  104.     do {
  105.        
  106.         fread (&temporal, sizeof(struct persona), 1, checker);
  107.  
  108.          if (edad_consulta == temporal.edad)
  109.         {
  110.            
  111.             printf("%s     %d     %sn", temporal.rut,  temporal.edad, temporal.nombre);
  112.          }
  113.  
  114.     } while (!feof(checker));   
  115.  
  116. }
  117.  
  118. // Función: Consulta por nombre
  119. void attribute_name()
  120. {
  121.     FILE *checker2;
  122.  
  123.     struct persona temporal2;
  124.  
  125.     char nombre_consulta[255];
  126.  
  127.     printf("Inserte el nombre a consultarn");
  128.     scanf("%*c%[^n]",nombre_consulta);
  129.  
  130.     checker2 = fopen ("archivo.dat", "rb");
  131.     if (checker2==NULL)
  132.         printf ("No se pudo abrir el archivon");
  133.     rewind(checker2);
  134.    
  135.     printf("Rut              Edad   Nombren");
  136.     printf("--------------------------------------------------------------------n");
  137.     do {
  138.        
  139.         fread (&temporal2, sizeof(struct persona), 1, checker2);
  140.  
  141.          if (nombre_consulta == temporal2.nombre)
  142.         {
  143.            
  144.             printf("%s     %d     %sn", temporal2.rut, temporal2.edad, temporal2.nombre);
  145.          }
  146.  
  147.     } while (!feof(checker2)); 
  148.  
  149. }
  150.  
  151. // Función: Consulta por rut
  152. void attribute_rut()
  153. {
  154.     FILE *checker3;
  155.  
  156.     struct persona temporal3;
  157.  
  158.      char rut_consulta[12];
  159.  
  160.     printf("Inserte el rut a consultarn");
  161.     scanf("%*c%[^n]",rut_consulta);
  162.  
  163.     checker3 = fopen ("archivo.dat", "rb");
  164.     if (checker3==NULL)
  165.         printf ("No se pudo abrir el archivon");
  166.     rewind(checker3);
  167.    
  168.     printf("Rut              Edad   Nombren");
  169.     printf("--------------------------------------------------------------------n");
  170.     do {
  171.        
  172.         fread (&temporal3, sizeof(struct persona), 1, checker3);
  173.  
  174.          if (rut_consulta == temporal3.rut)
  175.         {
  176.            
  177.             printf("%s     %d     %sn", temporal3.rut, temporal3.edad, temporal3.nombre);
  178.          }
  179.  
  180.     } while (!feof(checker3)); 
  181.  
  182. }
  183.  
  184. // Función: Consulta completa
  185. void generate_full()
  186. {
  187.     FILE *checker4;
  188.  
  189.     struct persona temporal4;
  190.    
  191.     checker4 = fopen ("archivo.dat", "rb");
  192.     if (checker4==NULL)
  193.         printf ("No se pudo abrir el archivon");
  194.     rewind(checker4);
  195.    
  196.     printf("Rut              Edad   Nombren");
  197.     printf("--------------------------------------------------------------------n");
  198.     do {
  199.        
  200.         fread (&temporal4, sizeof(struct persona), 1, checker4);
  201.         printf("%s     %d     %sn", temporal4.rut, temporal4.edad, temporal4.nombre);
  202.  
  203.     } while (!feof(checker4)); 
  204. }
  205.  
  206.  
  207. // Menú secundario de búsqueda por atributo,
  208. void attribute_search()
  209. {
  210.     int menu3_option;
  211.  
  212.     do {
  213.  
  214.     printf("1 Consulta por rutn");
  215.     printf("2 Consulta por nombren");
  216.     printf("3 Consulta por edadn");
  217.     printf("4 Generar listado completon");
  218.         scanf("%d", &menu3_option);
  219.  
  220.     switch (menu3_option)
  221.         {
  222.             case 1: printf("n");   
  223.                 attribute_rut();
  224.                 break;
  225.             case 2: printf("n");   
  226.                 attribute_name();
  227.                 break;
  228.             case 3: printf("n");   
  229.                 attribute_age();
  230.                 break;
  231.             case 4: printf("n");   
  232.                 generate_full();
  233.                 break;
  234.             default:
  235.                     printf("Opcion invalidan");
  236.                 break;
  237.         }
  238.  
  239.     } while ((menu3_option < 1) || (menu3_option > 4));
  240. }
  241.  
  242. // Opciones de menú
  243. int menu_option, menu_on = 1;
  244.  
  245. // Menú principal
  246. int main ()
  247. {   
  248.     do {
  249.  
  250.            
  251.         do {   
  252.             printf("n");   
  253.             printf("1 Crear tablan");
  254.             printf("2 Insertar tuplasn");
  255.             printf("3 Ver contenidon");
  256.             scanf("%d", &menu_option);
  257.  
  258.             switch (menu_option)
  259.             {
  260.                 case 1: printf("n");
  261.                     create_table_personas();
  262.                     break;
  263.                 case 2: printf("n");
  264.                     insert_into_table();
  265.                     break;
  266.                 case 3: printf("n");
  267.                     attribute_search();
  268.                     break;
  269.                 default: printf("n");
  270.                      printf("Opcion invalidan");
  271.                      break;
  272.             }
  273.  
  274.         } while ((menu_option < 1) || (menu_option > 3));
  275.  
  276.         printf("¿Desea realizar otra operacion? (1 Si, 0 No)n");
  277.         scanf ("%d", &menu_on);
  278.  
  279.     } while (menu_on == 1);
  280.  
  281. return (0);
  282.  
  283. }
  284.  
  285.  

Saludos.

alexg88

  • Miembro activo
  • **
  • Mensajes: 37
    • Ver Perfil
Re: [C] Estructuras y archivos binarios
« Respuesta #1 en: Domingo 8 de Mayo de 2011, 23:39 »
0
El problema del 4 que aparece es porque no lees bien las cadenas.

Una cadena en C se representa como un conjunto de caracteres terminado con el caracter .

Tú al leer de la forma que lo haces ( scanf("%*c%[^n]",data_save.rut);) no le estás poniendo el al final y por eso al imprimir con %s te da problemas porque no sabe donde finaliza la cadena.

Para leer cadenas se utiliza %s también.

Sobre el segundo problema, da porque la función feof no te devuelve true cuando debería (estoy revisando porque).

Otra cosa, la línea 37 (en la función insert_into_table), abres mal el fichero (da un pedazo de error).

Incorrecto:
 
Código: C
  1. save_file = fopen ("archivo.dat", "r+wb");
  2.  

Correcto (así abres para lectura y escritura):
 
Código: C
  1. save_file = fopen ("archivo.dat", "w+b");
  2.  

Amphoth3ra

  • Nuevo Miembro
  • *
  • Mensajes: 7
    • Ver Perfil
Re: [C] Estructuras y archivos binarios
« Respuesta #2 en: Domingo 8 de Mayo de 2011, 23:58 »
0
Cita de: "alexg88"
El problema del 4 que aparece es porque no lees bien las cadenas.

Una cadena en C se representa como un conjunto de caracteres terminado con el caracter .

Tú al leer de la forma que lo haces ( scanf("%*c%[^n]",data_save.rut);) no le estás poniendo el al final y por eso al imprimir con %s te da problemas porque no sabe donde finaliza la cadena.

Para leer cadenas se utiliza %s también.
¿Explícitamente que es lo que tengo que modificar? (si agrego me tira un aviso diciendo que el dice que está incrustado en el código).

Saludos.

alexg88

  • Miembro activo
  • **
  • Mensajes: 37
    • Ver Perfil
Re: [C] Estructuras y archivos binarios
« Respuesta #3 en: Lunes 9 de Mayo de 2011, 00:09 »
0
Primero tienes que hacer el array rut un caracter más grande para que puedas poner el .

Código: C
  1. struct persona {
  2.  char rut[12];
  3.  int edad;
  4.  char nombre[255];
  5.  };
  6.  

Segundo, las lecturas:
Código: C
  1.  
  2. printf("Rut de la personan");
  3.         scanf("%s",data_save.rut);
  4.         printf("Edad de la personan");
  5.         scanf("%d", &data_save.edad);
  6.         printf("Nombre de la personan");
  7.         scanf("%s",data_save.nombre);
  8.  
  9.  

Ya se porque te falla el feof. Resulta que para que feof te diga si el fichero ha terminado primero tienes que leer y luego realizar feof. Por eso te entra dos veces.
Tendrías que hacerlo así:
Código: C
  1.  
  2. void insert_into_table()
  3. {
  4.     void insert_into_table()
  5. {
  6.     int menu2_on = 1;
  7.  
  8.     struct persona avance;
  9.  
  10.     FILE *save_file;
  11.  
  12.     save_file = fopen ("archivo.dat", "w+b");
  13.  
  14.     fread (&avance, sizeof(struct persona), 1, save_file);
  15.  
  16.     if (avance.edad == 0)
  17.         rewind(save_file);
  18.  
  19.     do {
  20.         fread (&avance, sizeof(struct persona), 1, save_file);
  21.         do {
  22.             fread (&avance, sizeof(struct persona), 1, save_file);
  23.         } while (!feof(save_file));
  24.  
  25.         struct persona data_save;
  26.  
  27.         printf("Rut de la personan");
  28.         scanf("%s",data_save.rut);
  29.         printf("Edad de la personan");
  30.         scanf("%d", &data_save.edad);
  31.         printf("Nombre de la personan");
  32.         scanf("%s",data_save.nombre);
  33.        
  34.         fwrite (&data_save , 1 , sizeof(struct persona) , save_file);
  35.  
  36.         printf("¿Desea agregar otra tupla? (1 Si, 0 No)n");
  37.         scanf("%d", &menu2_on);
  38.  
  39.     } while (menu2_on == 1);
  40.  
  41.     fclose(save_file);
  42.  
  43.     struct persona junior;
  44.     FILE  *test_file;
  45.    
  46.     test_file = fopen ("archivo.dat", "rb");
  47.     if (test_file==NULL)
  48.         printf ("No se pudo abrir el archivon");
  49.  
  50.     printf("RuttEdadtNombren");
  51.     printf("--------------------------------------------------------------------n");  
  52.     fread (&junior, sizeof(struct persona), 1, save_file);
  53.     while (!feof(test_file))
  54.     {  
  55.         printf("%st%dt%sn", junior.rut, junior.edad, junior.nombre);        
  56.         fread (&junior, sizeof(struct persona), 1, test_file);      
  57.     }
  58. }
  59.  

Amphoth3ra

  • Nuevo Miembro
  • *
  • Mensajes: 7
    • Ver Perfil
Re: [C] Estructuras y archivos binarios
« Respuesta #4 en: Lunes 9 de Mayo de 2011, 01:15 »
0
De ahí te cuento como me salió, no te puedo decir mucho, pero solucioné los dos problemas que tenía.

Saludos.

ProfesorX

  • Moderador
  • ******
  • Mensajes: 796
  • Nacionalidad: mx
    • Ver Perfil
Re: [C] Estructuras y archivos binarios
« Respuesta #5 en: Lunes 9 de Mayo de 2011, 01:25 »
0
Bueno, ya te contestaron la mayoria de las dudas que tenias, solo añadire que no se recomienda el uso de scanf, ya que tiene el problema de que lee toda la entrada hasta que pulsas enter o encuentra un espacio.

Entonces ¿que pasa si tu defines tu cadena como de 12 caracteres, y por un error el usuario captura 15? pues que te guarda los 15 caracteres, pero como tu cadena es de 12, ocurre lo que se conoce como un desbordamiento de buffer, corrompiendo la memoria y con ella tu programa.

Cuando un programa es pequeño, estos desbordamientos no son fatales, pero en programas grandes si pueden serlo, ocasionando diversos problemas, entre ellos, el congelamiento o cuelgue del sistema.

Lo mas recomendable es usar fgets(), que te limita el total de caracteres que vas a leer, con esta funcion no puede haber un desbordamiento, ya que nunca leera mas de los caracteres que le digas que lea, aun cuando el usuario erronea o intencionalmente capture caracteres de mas. Claro que aun puede haber un desbordamiento de buffer si le dices que lea un maximo de 15, pero reservas para tu cadena menos de 15 caracteres, por ponerte un ejemplo.

Ademas, no es necesario que leas todo el archivo desde el principio para posicionarte al final del archivo, puedes usar la funcion fseek para esto, o abrir el archivo en modo append binario (ab+) si lo abres con append, automaticamente coloca el apuntador de archivo al final del archivo.

Te dejo el codigo que corregi, con comentarios para que quede mas claro :)

Código: C++
  1.  
  2. // Inserción en la tabla
  3. void insert_into_table()
  4. {
  5.     int menu2_on = 1;
  6.  
  7.     struct persona avance;
  8.  
  9.     FILE *save_file;
  10.  
  11.     save_file = fopen ("archivo.dat", "rb+");
  12.     // Coloca el apuntador de posicion de archivo al final del archivo
  13.     // No necesitas leer todo el archivo para posicionarte al final
  14.     // tambien podrias abrir el archivo con "ab+" en lugar de "rb+"
  15.     // y te evitas el tener que usar fseek
  16.     fseek(save_file, 0, SEEK_END);
  17.  
  18.     do {
  19.  
  20.         struct persona data_save;
  21.         // Variable de tipo cadena para capturar la edad con fgets, ya que fgets
  22.         // solo funciona con cadenas.
  23.         char edad[3];
  24.  
  25.         printf("Rut de la personan");
  26.         // Borra el buffer de entrada, para que no haya nada al leer los datos
  27.         // con fgets
  28.         while(getchar() != 'n');
  29.         // El tercer parametro es la longitud de tu cadena con el caracter de
  30.         // fin de cadena incuido. Si necesitas guardar 11 caracteres,
  31.         // debes reservar espacio para 12 (11+fin cadena). Si necesitas
  32.         // guardar 12, debes reservar espacio para 13, y asi, siempre
  33.         // debes reservar espacio para un caracter mas, que es el fin de cadena
  34.         fgets(data_save.rut, 12, stdin);
  35.  
  36.         printf("Edad de la personan");
  37.         while(getchar() != 'n');
  38.         fgets(edad, 3, stdin);
  39.         // Conviertes la edad
  40.         data_save.edad = atoi(edad);
  41.        
  42.         printf("Nombre de la personan");
  43.         while(getchar() != 'n');
  44.         fgets(data_save.nombre, 255, stdin);
  45.  
  46.         fwrite (&data_save , 1 , sizeof(struct persona) , save_file);
  47.  
  48.         printf("¿Desea agregar otra tupla? (1 Si, 0 No)n");
  49.         scanf("%d", &menu2_on);
  50.  
  51.     } while (menu2_on == 1);
  52.  
  53.     fclose(save_file);
  54.  
  55.     struct persona junior;
  56.     FILE  *test_file;
  57.  
  58.     test_file = fopen ("archivo.dat", "rb");
  59.     if (test_file==NULL)
  60.         printf ("No se pudo abrir el archivon");
  61.  
  62.     printf("Rut              Edad   Nombren");
  63.     printf("--------------------------------------------------------------------n");  
  64.     while (!feof(test_file))
  65.     {  
  66.         fread (&junior, sizeof(struct persona), 1, test_file);
  67.         // Necesitas volver a comprobar si despues de leer llegaste al final del archivo
  68.         if (!feof(test_file))
  69.         {
  70.             printf("%s     %d     %sn", junior.rut, junior.edad, junior.nombre);  
  71.         }
  72.  
  73.     }
  74.  
  75.     // No olvides cerrar tus archivos
  76.     fclose(test_file);
  77. }
  78.  
  79.  

Saludos :)

NOTA:
==================================================================
Este foro es para ayudar, aprender, compartir... usenlo para eso,
NO SE RESUELVEN DUDAS POR MENSAJE PRIVADO Y MENOS POR CORREO
==================================================================

Amphoth3ra

  • Nuevo Miembro
  • *
  • Mensajes: 7
    • Ver Perfil
Re: [C] Estructuras y archivos binarios
« Respuesta #6 en: Sábado 14 de Mayo de 2011, 15:38 »
0
Bueno, en el programa final usé scanf y no fgets, aunque igual me funcionaba, lo tomaré en cuenta para después. El feof funcionó tal cual como me dijeron, el dato no se guardaba duplicado.

Saludos.