[ Foro de C ]

Limpiar de basura la memoria donde va el fichero

25-Oct-2009 22:07
Jesús S.
5 Respuestas

¡Hola!

Al trabajar en el ejemplo de la página 93, me he encontrado que hay basura almacenada en el fichero, sobre todo hacia el final.

Esto, para contar las fichas que están rellenas o vacías, o para alguna condición basada en que la ficha esté llena o vacía, puede dar lugar a resultados insospechados.

¿Hay alguna forma de limpiar la memoria que va a ocupar el fichero, antes de rellenar las fichas? Cuando se abra de nuevo ¿puede volver a aparecer basura?.

Ahora, conociendo cuántas fichas he rellenado, pensaba hacer un bucle en programa aparte que me dejase en blanco las fichas no ocupadas. Posteriormente se podría poner como función en el propio ejercicio. Pregunto lo mismo ¿me volverá a aparecer basura?

Saludos.


27-Oct-2009 00:31
Nacho Cabanes (+83)

No es necesario limpiar basura. Y de hecho, el hacerlo sería más lento, por lo que un compilador de C no lo hará a no ser que se lo pidas.

Por ejemplo, cuando tú reservas espacio para un char[30], si lees con gets o scanf una cadena de 4 letras (más el caracter nulo de final), tendrás 25 caracteres de basura a continuación de esos 5 útiles.

Y claro, si vuelcas a fichero esos 30 bytes, 25 de ellos seguirán siendo basura en el fichero. Pero no es problema: cuando se lee del fichero, el 5º byte es un \0, por lo que no se lee más allá y se ignora esa basura, que seguirá existiendo pero no supondrá ningún problema.

Si quisieras reemplazar esa basura por caracteres nulos o por espacios (por ejemplo, porque quisieras poder editar los datos del fichero con un editor de texto convencional), lo podrías hacer con una orden "for", o, más rápido, con la orden "memset", que rellena un bloque de bytes con un cierto valor.


27-Oct-2009 23:10
Jesús S.

¡Hola!

Gracias profe por la rápida y certera contestación. Pero me pasa lo siguiente. He creado un fichero de texto (agendilla.txt), que si lo abro con el bloc de notas, está perfecto, ni basura ni nada por el estilo. Voy a copiarlo a las estructuras e imprimir SÓLO LAS FICHAS QUE ESTÁN RELLENAS para lo que uso el siguiente programa. La condición que pongo es que el nombre sea "\0".
Lo imprime fenómeno, pero al final sigue con una ficha más que las que están rellenas poniendo lo siguiente:

              28/12/198
              28/12/19
              28/12/1
              28/12/
              28/12
                      28
              28/
              28/ 0/   0
y se para al comienzo de la impresión de la siguiente ficha.

La fecha que figura en la última ficha válida es 28/12/1983.
Pregunto:
Si abro el fichero con el bloc de notas (Windows XP) y veo que está perfecto ¿Puede, a pesar de todo, contener basura que no la detecta el bloc de notas? ¿O la ha generado el programa de lectura?
Entiendo que si quiero dejar una variable de carácter en blanco sólo tengo que poner, por ejemplo, char a ="", pero ¿Cómo se puede dejar vacía o en blanco una variable numérica?.

Perdonadme si me salgo un poco de los temas candentes.

Saludos.

/*Lectura de las fichas rellenas de un archivo de texto*/

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

#define TAMANO 100
 
typedef struct
 {
   short int dia;
   short int mes;
   short int anyo;
 }fecha;

typedef struct {
   char nombre[40];
   char apellidos[60];
   char direccion[80];
   char codpostal[10];
   char poblacion[50];
   unsigned int telefono;
   char email[50];
   fecha fechaNacim;
}registro;

     FILE* fichero;


main()

  {
     char titulo[100] ="J:\\Lenguajes_Programacion\\Lenguaje_C\\Nachocabanes\\Ejercicios\\Ficheros\\agendilla.txt";
     char linea [81], textemp[81];
     int a =0;
     registro ficha[TAMANO];
     
     fichero = fopen(titulo, "rt");
     
     while (! feof(fichero))      {
           fgets(linea, 80, fichero);
           linea[strlen(linea) -1] ='\0';
           strcpy (ficha[a].nombre, linea);
           puts(ficha[a].nombre);
           if(ficha[a].nombre == "\0") break;
           fgets(linea, 80, fichero);
           linea[strlen(linea) -1] ='\0';
           strcpy (ficha[a].apellidos, linea);
           puts(ficha[a].apellidos);
           fgets(linea, 80, fichero);
           linea[strlen(linea) -1] ='\0';
           strcpy (ficha[a].direccion, linea);
           puts(ficha[a].direccion);                        
           fgets(linea, 80, fichero);
           linea[strlen(linea) -1] ='\0';
           strcpy (ficha[a].codpostal, linea);
           puts(ficha[a].codpostal);
           fgets(linea, 80, fichero);
           linea[strlen(linea) -1] ='\0';
           strcpy (ficha[a].poblacion, linea);
           puts(ficha[a].poblacion);            
           fgets(linea, 80, fichero);
           linea[strlen(linea) -1] ='\0';            
           strcpy(textemp, linea);
           /*Pasar texto a numero*/  
           sscanf (textemp, "%10u", &ficha[a].telefono);
           printf("%10u\n", ficha[a].telefono);
           fgets(linea, 80, fichero);
           linea[strlen(linea) -1] ='\0';
           strcpy (ficha[a].email, linea);
           puts(ficha[a].email);            
           fgets(linea, 80, fichero);
           linea[strlen(linea) -1] ='\0';            
           strcpy(textemp, linea);
           /*Pasar texto a numero*/  
           sscanf (textemp, "%2hd/%2hd/%4hd", &ficha[a].fechaNacim.dia,
                                              &ficha[a].fechaNacim.mes,
                                              &ficha[a].fechaNacim.anyo);            
           
           printf("%2hd/%2hd/%4hd\n\n",ficha[a].fechaNacim.dia,
                                   ficha[a].fechaNacim.mes,
                                   ficha[a].fechaNacim.anyo);
           a++;              
           
           }
     
     getch();
     fclose(fichero);
     
     return;
     }


29-Oct-2009 21:03
Jesús S.

¡Hola de nuevo!

Amplio datos sobre el problema. Donde se genera el problema es cuando escribo las fichas en el fichero. Si escribo cuatro fichas, cuando las leo me aparecen las cuatro más la propina.

Sin embargo, si leo el archivo de texto con el bloc de notas o con word, no me detectan la ficha pirata. ¿Puede ser por algún eco del DOS? Va quitando un número a la fecha en cada línea.

La forma de introducir los datos es como la indico a continuación, donde cont es la cantidad de fichas escritas hasta el momento. Pongo cont-1 para sobreescribir la ficha pirata al escribir las nuevas, pero al final de estas me aparece de nuevo con los valores de la última fecha que haya escrito.

  printf("¿Quieres escribir fichas nuevas, si o no?");
  gets(decision);
 
  if(strcmpi(decision,"SI")!=0)
      break;
  else  {
             i = cont-1;            
      sigue1:

      puts("Escribe el nombre");
      gets(ficha[i].nombre);
      if(strlen(ficha[i].nombre)==0) break;
      fputs(ficha[i].nombre,fichero);
      fputs("\n",fichero);  

      puts("Escribe los apellidos");
      gets(ficha[i].apellidos);
      fputs(ficha[i].apellidos,fichero);    
      fputs("\n",fichero);  
     
      puts("Escribe la direccion");
      gets(ficha[i].direccion);
      fputs(ficha[i].direccion,fichero);
      fputs("\n",fichero);          
     
      puts("Escribe el Codigo Postal");
      gets(ficha[i].codpostal);
      fputs(ficha[i].codpostal,fichero);
      fputs("\n",fichero);          
     
      puts("Escribe la poblacion");
      gets(ficha[i].poblacion);
      fputs(ficha[i].poblacion,fichero);    
      fputs("\n",fichero);  
     
      printf("Escribe el telefono\n");
      gets(textemp);
      sscanf(textemp,"%10u",&ficha[i].telefono);
      fprintf(fichero,"%10u",ficha[i].telefono);
      fputs("\n",fichero);
             
      puts("Escribe el email");
      gets(ficha[i].email);
      fputs(ficha[i].email,fichero);
      fputs("\n",fichero);                
             
      printf("Escribe el dia mes y anyo, numeros separadoss por espacio\n");
      gets(textemp);
      sscanf(textemp,"%2hd %2hd %4hd",&ficha[i].fechaNacim.dia,
                                      &ficha[i].fechaNacim.mes,
                                      &ficha[i].fechaNacim.anyo);
      fprintf(fichero,"%2hd/%2hd/%4hd",ficha[i].fechaNacim.dia,
                                       ficha[i].fechaNacim.mes,
                                       ficha[i].fechaNacim.anyo);
      fputs("\n",fichero);        
     
      printf("¿Quieres escribir otra ficha, si o no?\n");
      gets(decision);
      if(strcmpi(decision,"SI")!=0) {fclose(fichero);break;}
      ++i;
      goto sigue1;
      }


01-Nov-2009 10:41
Jesús S.

¡Hola!

Resumo los problemas:

Cuando escribo las fichas en el fichero, el programa añade una más, tal como lo he descrito.

Cuando leo el fichero con el bloc de notas SÍ veo la basura. No existe el problema que yo decía.

Con vuestra ayuda y comentarios, el programa me ha quedado estupendo (excepto lo indicado), por lo que paso a los binarios.

Saludos








01-Nov-2009 21:33
Nacho Cabanes (+83)

Sobre cada uno de tus problemas:

- Cuando escribo las fichas en el fichero, el programa añade una más, tal como lo he descrito.

Lo habitual es que eso no ocurra exactamente cuando escribes en el fichero, sino cuando lees: según plantees la comprobación de final de fichero, es muy frecuente que "creas leer" una ficha más de las que realmente hay.

Me explico: cuando terminas de leer la última ficha, todavía no ha fallado el intento de lectura, y por tanto todavía no se ha marcado el final de fichero como alcanzado ("feof" sigue siendo "falso").

Si entonces lees una ficha completa, dando por sentado que podrás hacerlo, ésta contendrá basura. Realmente deberías intentar leer el nombre (preferiblemente en una variable temporal), y si sigue si haber "feof" entonces sigues leyendo el resto.

- Cuando leo el fichero con el bloc de notas SÍ veo la basura. No existe el problema que yo decía.

Aun así, existe un caracter ASCII que es la marca de fin de fichero, y otros caracteres de control que el Bloc de notas no sabría interpretar, así que sí puede ocurrir que haya basura pero no la veas.

- Con vuestra ayuda y comentarios, el programa me ha quedado estupendo (excepto lo indicado), por lo que paso a los binarios.

Duro con ello! Los ficheros binarios en C no son excesivamente fáciles, pero al menos son más previsibles que los de texto.






(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.)