[C con Clase] problemas con la posicion del puntero en un fichero, funciones fread, frwite, fseek etc.

Albert Montolio albert.montolio en gmail.com
Lun Mar 5 22:30:19 CET 2012


Hola, he intentado siguiendo tus indicaciones solucionar el problema, he
creado un contador, que recorre el fichero, y ahora lee todo ordenador, a
mas con la funcion feof nueva ya no se va hasta el infinito. el problema
ahora esta en la primera palabra que lee y la ultima.
la primera palabra no la lee, va directo a la segunda, y la ultima palabra
no la repite infinitamente, xo la repite 1 vez mas, es decir, la pone dos
veces. no se como solucionarlo, ya que el contador con i=0 indica clarament
que lea la primera palabra, y con la funcion feof, en teoria, no tendria k
volver a entrar en el while, por tanto, no entiendo porque repite la ultima
palabra antes de acabar.
muchas gracias por la ayuda, pego la nueva version a continuacion

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


struct t_palabra {                      // t_palabra es una estructura que
contiene castellano ingles y contadores de aciertos y fallos
       char castellano[30];
       char ingles[30];
       int cont_aciertos;
       int cont_errores;
       };


int main (void)

{
    FILE *fichero;                       // apunta al fichero donde se
guardaran las palabras y sus aciertos/fallos
    struct t_palabra palabra;            // definim la variable paraula.
    char respuesta[50];                  // l'usuari entra la seva resposta
    int i;                               // recorrer el ficher

struct t__virt_palabra {                    // l'utilitzo per augmentar els
contadors cada cop k l'usuari practica 1 paraula. (nose una altre manera de
fer-ho)
       char virt_castellano[30];
       char virt_ingles[30];
       int virt_cont_aciertos;
       int virt_cont_errores;
       };
struct t__virt_palabra virt_palabra;        // definim la variable
virt_palabra

    fichero = fopen ("datos.dat", "rb+");              // s'obre el ficher
datos.dat. rb+ es correcte????? al ficher hi ha tant caracters
                                                       // castellano,
ingles, com enters (els contadors) x tant te que ser binari, no?

    if (fichero == NULL)                                 // salta en cas
que no existeixi l ficher datos.dat
       printf ("Error: No se ha podido abrir el fichero datos.dat.");

    else
    {
        i=0;
        strcpy (respuesta, "hola");
        virt_palabra.virt_cont_aciertos = 0;
        virt_palabra.virt_cont_errores = 0;

        fseek(fichero, i*sizeof(struct t_palabra), SEEK_SET); // se pone el
cursor al inicio de todo xk i=0

        while (!feof(fichero))                        // preguntar al
usuari paraules, fins k sarrivi a la ultima paraula,
        {                                                     // despres
d'aquesta tindria que parar!!!!! i no ho fa :s, tornar a preguntar
                                                              // sempre la
ultima :(
            if(fread(&palabra, sizeof(palabra), 1, fichero)) {

            fread(&palabra, sizeof(palabra), 1, fichero);     // en la
primera iteracio, llegirm la primera paraula gracies a i=0
            printf ("\nEscribe la traduccion de...: ");       // preguntem
la paraula
            printf ("\n%s: ", palabra.castellano);
            gets(respuesta);                                  // l'usuari
entra la paraula

            // analitzar si l'usuari la encertat, o fallat, i incrementar
els contadors corresponents x cada paraula
                            if (strcmp(respuesta, palabra.ingles) == 0)  //
compara resposta amb palabra.ingles si es correcte...
                            {
                            printf ("\nCorrecto!");           // felicitem
al usuari x cortesia, tenim que incrementar el contador d'encerts

                                   // com que no es pot modificar nomes 1
apartat de la estructura paraula, tenim que introduir de nou tot...
                                   // copiem a la variable virtual (nomes
serveix x traspar informacio) la paraula i la seva traduccio
                                   strcpy (virt_palabra.virt_castellano,
palabra.castellano);
                                   strcpy (virt_palabra.virt_ingles,
palabra.ingles);
                                   // incrementem el contador una unitat
                                   //palabra.cont_aciertos a la primera
iteració val 0 (aixi sa inicialitzat)
                                   // i ho guardem a la virtual tb, x tal d
copiar tot again.
                                   virt_palabra.virt_cont_aciertos =
palabra.cont_aciertos + 1;

                                   // important: com que hem utilitzat
fread, el curso esta darrera la paraula llegida ara!!
                                   // la variable virtual conte les noves
dades, es a dir, amb el contador incrementat,
                                   // x tant, tenim que ficar el cursor al
inici de la paraula k estavem treballant, xk
                                   // escrigui la informacio just a sobre
de la paraula antiga
                                   // ara la i estava a la posicio dspres
de size of (equivalent a i=0), es a dir, dspres de la primera paraula
                                   // en la primera iteració, ja que la i
val 0, amb aquesta comanda tornem a la posicio inical

                                   fseek(fichero, i*sizeof(struct
t_palabra), SEEK_SET);

                                   strcpy (palabra.castellano,
virt_palabra.virt_castellano);
                                   strcpy (palabra.ingles,
virt_palabra.virt_ingles);
                                   palabra.cont_aciertos =
virt_palabra.virt_cont_aciertos;

                                   // i podem sobreescriure la paraula que
voliem

                                   fwrite (&palabra, sizeof(palabra), 1,
fichero);
                                   // important, el cursor torna a estar
darrera de la primera paraula (en primera iteracio)


                            }      // sino es correcte...


                            else
                                {

                                printf ("\nIncorrecto.");


                                   virt_palabra.virt_cont_errores =
palabra.cont_errores + 1; // mateixa estrategia
                                   strcpy (virt_palabra.virt_castellano,
palabra.castellano);
                                   strcpy (virt_palabra.virt_ingles,
palabra.ingles);

                                   fseek(fichero, i*sizeof(struct
t_palabra), SEEK_SET);

                                   strcpy (palabra.castellano,
virt_palabra.virt_castellano);
                                   strcpy (palabra.ingles,
virt_palabra.virt_ingles);
                                   palabra.cont_errores =
virt_palabra.virt_cont_errores;



                                   fwrite (&palabra, sizeof(palabra), 1,
fichero);
                                   // important, ara el cursor esta despres
de la paraula treballada

                                }

            // hem acabat la primera iteracio


            i++; // incrementem la i, per tal danar a la propera paraula.
            fseek(fichero, i*sizeof(struct t_palabra), SEEK_SET);   //
coloquem el cursor a la seguent posicio, es a dir, a la posicio 1,
                                                                    // es a
dir, a la segona paraula. nem cap a dalt, ja que al ficher
                                                                    //
encara hi ha paraules, i tooorneeem a fer el while.
            }
            else {
                 printf ("\nfin!");
                 }
            }


        fclose (fichero);


        }


fflush(stdin);
printf("\n\nPulse Intro para finalizar...");
getchar();



}




El 5 de marzo de 2012 10:35, Salvador Pozo <salvador en conclase.net> escribió:

> El pasado 2012-03-04 22:23:19, Albert_Munich escribió:
>
> A> Muchas gracias por la explicación,
> A> he corregido lo de SEEK_CUR, y ahora en teoria, lee la palabra, el
> cursor
> A> se queda despues de la palabra, y para sobreescribirla utilizo
> A> fseek(fichero, (-1)*sizeof(struct t_palabra), SEEK_CUR);
> A> y tampco me funciona, me repite todo el rato la segunda palabra, el
> mismo
> A> problema de siempre. no entiendo el porque, ya que despues del fwrite,
> el
> A> cursor queda detras d la palabra modificada, y con el siguiente fread
> A> dentro dl while, se tendria que leer la palabra que toca. no se como
> A> solucionarlo xk x logica lo haria asi, xo nose donde esta el error
> A> informatico, o si esta equivocada la logica aplicada.
> A> Me podrias ayudar? esque estoy aprendiendo a programar x mi cuenta y
> cuesta
> A> 1 poco.
>
> Hola:
>
> Bueno, mucho me temo que esta es una de esas "cosas raras" que pasan con
> la programación, cuando el lenguaje está limitado con respecto a las
> implementaciones reales de los sistemas operativos.
>
> Puede que me equivoque en el origen del problema (si es así, que alguien
> me corrija), pero me temo que este comportamiento de las funciones de
> ficheros está relacionada con el modo en que Windows implementa el sistema
> de archivos.
>
> En C++, usando streams, es posible que esto no pase, pero luego llegamos a
> esto.
>
> Los ficheros de acceso aleatorio pueden tener punteros de escritura y
> lectura diferentes, es decir, el punto en que se lee del fichero no tiene
> por qué ser el mismo en el que se escribe. Esto es evidente si el fichero
> se abre en modo "append", en los que podemos leer de cualquier punto, pero
> sólo se puede escribir al final. Pero lo cierto es que puede pasar en todos
> los tipos de ficheros.
>
> En tu programa fseek coloca los dos cursores del fichero, el de escritura
> y el de lectura, a a una posición anterior, pero al escribir los nuevos
> valores del registro sólo se actualiza el cursor de escritura, y el de
> lectura se mantiene en la misma posición. Por eso siempre leemos el segundo
> registro.
>
> Los streams de C++ disponen de funciones diferentes para colocar los
> cursores de lectura y escritura: seekg y seekp, y lo mismo para leer esas
> posiciones: tellg y tellp. Por lo que esto resulta más evidente.
>
> La solución es simple: colocar el cursor antes de realizar cada lectura.
> Para esto necesitarás un índice.
>
> Otro problema con tu programa es el uso de feof (creo que lo habías
> preguntado anteriormente).
>
> El bucle tiene esta forma:
> ----8<------
> while(!feof(fichero)) {
>    fread(&palabra, sizeof(palabra), 1, fichero);
>    ...
> }
> ----8<------
>
> Ahora imaginemos que hemos leído el último registro, y volvemos a repetir
> el bucle.
> Primero, la condición de fin de fichero es falsa, ya que es una bandera
> (un flag) que se almacena en la estructura FILE, y que sólo se actualiza
> después de una operación de lectura o escritura.
> Como feof es falsa, !feof es verdadera, y se ejecuta el bucle. Leemos una
> palabra, pero el cursor de lectura está al final del fichero, de modo que
> la lectura falla, y se activa la bandera de fin de fichero. Sin embargo, se
> procesa el registro.
> Cuando fread falla, el registro no se lee, de modo que palabra mantiene su
> valor actual. Esto hace, en un bucle normal (sin fseek), que el último
> registro se procese dos veces. En tu caso, el último registro se procesa
> hasta el infinito.
>
> En el caso de los ficheros hay que modificar este bucle:
> ----8<------
> while(!feof(fichero)) {
>    if(fread(&palabra, sizeof(palabra), 1, fichero) {
>       ...
>    }
> }
> ----8<------
>
> Es decir, sólo procesamos el registro leído si realmente lo hemos leído.
>
> Sobre este tema puede consultar la página de C con Clase sobre archivos:
> http://c.conclase.net/ficheros/index.php
>
> Hasta pronto.
>
> --
> Salvador Pozo (Administrador)
> mailto:salvador en conclase.net
> _______________________________________________
> Lista de correo Cconclase Cconclase en listas.conclase.net
> http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
> Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ
>
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listas.conclase.net/pipermail/cconclase_listas.conclase.net/attachments/20120305/c1d94dea/attachment.html>


Más información sobre la lista de distribución Cconclase