Problema con fgets

Hola,

Después de buscar y buscar, no encuentro la solución a mi problema. Estoy haciendo un programa en C que utiliza ficheros.
Tengo un fichero donde introduzco caracteres con getstr ya que gets en Linux, gcc da aviso.
Una vez introducido caracteres queda asi el fichero:

una linea con espacios
otra con espacios

Utilizo getstr ya que quiero poder leer con espacios, no sé si me explico. Bueno una vez tengo el fichero ya creado, quiero leer lo que hay en el e imprimirlo con printf.
Así que abro el fichero con fopen() y pongo

fgets (variable, caracteres que quiero leer, nombre fichero);
printf ("%s", variable);

pues al hacer esto, parece que no lo lee ya que no me muestra nada por pantalla, he probado de hacerlo con fscanf, y si que me lo muestra, claro que solo hasta el primer espacio y a mi me interesa que me muestre toda la linea.

Perdonad si no me he explicado claramente ya que tengo la cabeza un poco liada y es muy tarde. He estado buscando mucho y no encuentro como solucionarlo.
Si quereis subo el archivo para que lo veais más claramente.

Gracias!
Visto que nadie ha respondido, yo estoy empezando con C, si pones el código para verlo mejor igual puedo ayudar en algo. Si he entendido bien lo que quieres decir, no veo nada incorrecto en el uso de fgets, no sé.

Saludos
Por qué no usas open,close,read,write ?

Salu2.Ferdy
tambien puedes usar getline, que lee hasta el retorno de carro, pero mejor que gets (que es un buffer overflow andante xD)
No he utilizado fread y fwrite porque no lo hemos dado, pero al final lo voy a hacer con eso.
Lo que no acabo de entender es eso de los bytes, ya que el fichero entra en binario los caracteres no?
Es decir yo en el fichero voy a meter 4 strings, uno de 30 caracteres de longitud como máximo el segundo y tercero de 20 y el ultimo de 10.
Que tendría que poner en fwrite?
Gracias por todo, voy muy mal de tiempo y por eso no puedo mirarmelo mejor, pero hago todo lo posible.
fwrite: recibe una dirección de memoria, el número de bytes que ocupa el dato, el número de datos a escribir y un fichero. Este es su prototipo:

int fwrite( void * direccion, int tam, int numdatos, FILE * fichero);
Escribe en el fichero los tam por numdatos bytes existentes desde direccion en adelante. Devuelve el número de datos que ha conseguido escribir (si vale menos que numdatos, hubo algún error de escritura).

Sacado de: http://marmota.act.uji.es/IG04/pdf/c.pdf

Por ejemplo:

fwrite(variable, 1, 30, fich)
donde variable es la cadena que quieres escribir (tambien puede ser *entero donde entero es de tipo int...), 1 es el tamaño del dato (1 byte), 30 es la cantidad de caracteres (bytes), fich es el FILE * .

Yo lo uso con registros, entonces el uso es:

fwrite( & reg, sizeof(struct registro), x, fich);

donde x es un entero (cantidad de datos del tipo struct registro a escribir), reg es del tipo struct registro y fich del tipo FILE *

Espero que sea esto lo que pidas, porque después de todo el rollo...

Saludos

PD: para escribir datos de distinto tamaño, deberás saber el orden para después leerlos bien, con el mismo tamaño. Por lo menos hasta donde me han explicado. Supongo que habrá formas de hacerlo más elegantes y potentes pero yo aún estoy verde en esto.
Gracias!!!

Ya me funciona todo bien con fread y fwrite, el unico problema que me lo mirare esta noche esque parece que no funciona el feof(file) ya que la ultima palabra del fichero se me repite dos veces, pero por lo demas genial.
Estás usando un bucle para leerlo?
Si posteas el codigo antes de las 2 igual puedo mirar lo del feof(file). Yo solo he trabajado con binarios que guardan datos del mismo tipo entonces uso:

while(fread(& registro, sizeof(registro),1, file)==1){
............
}

Cuando sea distinto de uno saldrá del while porque habrá acabado de leer.
El codigo es el siguiente (un trozo que sino, con lo mal que va EOL lo tiro ; P)
Pues bien:

while (!feof(fp)){
      fread (peli.titulo, sizeof(1), 30, fp);
      fread (peli.director, sizeof(1), 20, fp);
      fread (peli.protagonista, sizeof(1), 20, fp);
      fread (peli.genero, sizeof(1), 10, fp);
      if (!strcasecmp(peli.titulo, compeli.titulo)){
         printw ("\n%s", peli.titulo);
         printw ("\t\t%s", peli.director);
         printw ("\t\t%s", peli.protagonista);
         printw ("\t\t%s", peli.genero);
      }
   }


Es decir, si busco (compeli.titulo), por ejemplo "Linux", quiero que me muestre todas las peliculas que se llaman "Linux" y que de cada una de ellas me diga el autor, etc.
Eso me funciona, solo que si la última pelicula que hay en el fichero tiene como titulo "Linux" me sale dos veces. Si Hago que me salga otra pelicula, por ejemplo "EOL" y esa esta por mitad del fichero solo me sale una vez, como tiene que ser.
Buenas de nuevo,

realmente no sé porque el bucle no funciona como tu pretendes. De todos modos, yo creo que un modo más cómodo de trabajar con esos datos sería definiendo un tipo de registro tal que así:

struct Peli {
char titulo[30];
char director[20];
char protagonista[20];;
char genero[10];
};

Así, a la hora de leer el fichero binario podrías leerlo del siguiente modo:

while(fread(&pelicula,sizeof(struct Peli),1,fp)==1){
if (strcmp(peli.titulo, compeli.titulo)==0){
//Mostrar datos de la peli
}

//considerando pelicula de tipo struct Peli
//fread devuelve el número de datos leídos

//para almacenar los datos en el binario para después hacer consultas sobre él , una vez leídos los datos por teclado,puedes hacer:
//fwrite(&pelicula,sizeof(struct Peli),1,fp);
//suponiendo de nuevo la variable pelicula del tipo struct Peli

PS: la longitud de las cadenas de los datos de la peli definidas en struct Peli mejor definirlas como constantes.
PS2: las indentaciones no salen ;)
PS3: Siento haber tardado tanto en contestar pero no he estado en casa desde ayer a mediodía. Supongo que ya lo habrás resuelto pero en fin...

Saludos
Zeenek se repite dos veces dado que no comprueba correctamente el final del fichero, hazte una función que con fseek y ftell calcule el final del fichero, y retornas ese valor ( es decir el numero de estructuras de datos que hay en el fichero ) y el bucle que sea hasta que sea igual a ese valor de retorno.

fread (peli.titulo, sizeof(1), 30, fp);
fread (peli.director, sizeof(1), 20, fp);
fread (peli.protagonista, sizeof(1), 20, fp);
fread (peli.genero, sizeof(1), 10, fp);

Y referente a este codigo de arriba, puedes escribir la estructura de datos entera y leerla entera, no tendrias que sacar cada uno de sus campos ( es un engorro ) .

Venga un saludo.

PD: si tengo tiempo te posteo un ejemplo de esa función.
No he conseguido solucionar eso ya que no he tenido tiempo, tengo otros proyectos a parte y consumen todos los recursos de mi CPU ; P

Adjunto el código fuente, por favor, no os riais del código, ya que no sé programar "bien", como ya sabeis para compilarlo, gcc con -lncurses.

Otro problema que me ha surgido es que he querido aumentar el tamaño de los strings a 50 cada uno, y ahora me da violación de segmento, supongo que es porque no tendré que poner el 1 en sizeof(), y no se que número poner para que no me de violación de segmento, pero bueno, este problema no es "urgente" ya que si se quedan con el tamaño que están me conformo.

Gracias a todos.

Adjuntos

Buenas,

Acabo de echarle un vistazo al código (se nota que vienen los exámenes y tengo pocas ganas de estudiar? ).
Has trabajado en clase con ficheros binarios o sabes como van? En el caso de que no sepas como funcionan y quieras mirártelo échale un vistazo al tema 5 del link que te puse posts atrás.

El problema que le veo es que estás usando mal las funciones fread y fwrite. Te he modificado las funciones mintro y bpeli, para guardar las pelis en fichero binario y leerlas de él, para que veas como va más o menos. El problema es si guardas datos de distintos tipos, pero en tu caso creo que serán todos del tipo struct pelicula, entonces no hay problema.

PS: Con respecto al código, yo lo veo bastante claro ya que no tengo ni idea de ncurses y más o menos entiendo lo que hace.

PS2: lo de las funciones fread y fwrite las uso en binarios y fgets, fscanf, fprintf... en ficheros de texto. Pero supongo que se podrán usar de otro modo y habrá mejores opciones, aún no las conozco ;)

Si no has trabajado con binarios y quieres hacerlo en ficheros de texto, no te marees con lo que te he dicho y hazlo como sabes. No es el momento de liarse con cosas nuevas teniendo los exámenes tan cerca.


PS3: Respecto a lo de aumentar la longitud de las cadenas con modificar el registro struct pelicula y leer bien los datos del fichero no deberías tener más problemas.

Si me olvido algo dímelo, si decides usar binarios dilo y te comento algo más.
Cualquier duda ya sabes donde estoy, a ver si puedo ayudar. Saludos y suerte con los exámenes y demás proyectos.

Siento el tostón :D

Edito: se me olvidó adjuntar y no recuerdo como se hacía, voy a ver.
Por cierto, al compilar con -Wall da algún warning, miratelo si eso.

Oye que no me deja responder para adjuntar el fichero, que dice que hace poco tiempo que escribí, por lo menos hace un cuarto de hora, cuanto hace falta?
Tampoco me deja opción de adjuntar editando.
Sí, es una putada. Tienes que borrar el mensaje (guardalo primero ;)) y volverlo a postear con el adjunto, es una puñeta esta nueva norma.
Aunque ahora que he posteado yo ya puedes. :)

Un saludo.
Entonces no se pueden escribir dos posts seguidos? Vaya, en fin, será mejor si así lo han decidido. Gracias musikal ;)

Adjuntos

Holas!

Yo también estoy empezando en esto... pero bueno, lo de los ficheros binarios más o menos te podría echar una mano en dudas (que desgraciadametne tb estamos de exámenes). De texto he utilizado poquito pero no sé, yo en este caso lo veo más para una fichero binario que para uno de texto, no?

Una preguntilla para NeoRave... ¿fread devuelve el número de elementos leídos? Se supone que como siempre lees un elemento si te devuelve otro valor es que termina el fichero? Y entonces... se supone que cuando termina el fichero no leería ningún elemento, cierto?
Lo digo porque yo, con lo poco que sé, siempre he utilizado por por ej
while(!feof(f)).

Igual esta tarde ó mañana os pido a ver si me podéis resolver algunas dudillas de punteros... ein?.

Gracias.

Un saludo.
A parte de lo que te comentan por aquí, para evitar que gets te de error, (te de error porque desconoce la longitud de la linea que vas a introducir y podría sobrepasar el tamaño del buffer interno que usa), usa fgets(variable,255,stdin); por ejemplo y te leera del teclado 255 caracteres, en este caso conoce el numero de bytes a leer y no tiene problema. Un saludo.
ChankyFanky escribió:¿fread devuelve el número de elementos leídos? Se supone que como siempre lees un elemento si te devuelve otro valor es que termina el fichero?


Sí, fread devuelve el número de elementos leídos. Si lees de uno en uno, cuando el valor devuelto por fread sea distinto de uno será que ha terminado de leer.

ChankyFanky escribió:Y entonces... se supone que cuando termina el fichero no leería ningún elemento, cierto?


No te entiendo. Si usas

while(fread(&pelicula,sizeof(struct Peli),1,fp)==1){

Cuando no devuelve uno, sale del bucle y ha acabado de leer el contenido del fichero.

Edito:
Jaime escribió:usa fgets(variable,255,stdin); por ejemplo y te leera del teclado 255 caracteres, en este caso conoce el numero de bytes a leer y no tiene problema.


Gracias por el apunte, esto sirve para evitar el buffer overflow no? No había caído en ese método.

Saludos
NeoRave escribió:

Sí, fread devuelve el número de elementos leídos. Si lees de uno en uno, cuando el valor devuelto por fread sea distinto de uno será que ha terminado de leer.


Hombre técnicamente no tiene que ser así, te recomiendo otro tipo de formas de ver si ha acabado de leer, porque puede que te de diferente a 1 por algún error y no se porque ha acabado de leer, no se a mí en una práctica me lo pondrían mal, te recomiendo más otra forma de hacerlo ;). Un saludo.
Hombre, eso está claro pero de momento yo estoy en primero y aún no hemos trabajado con los tipos de errores. Pero en caso de necesidad de tener en cuenta estos errores, cada uno sabrá que entra en su temario y que le exigen en sus prácticas y/o exámenes.

Sería válido un:

fseek(fp, 0, SEEK_END); ftell(fp)
y comparar con el valor devuelto por ftell, no?

Y si comparas fread con 0 y cuando sea cierto sales del bucle?

En fin, lo dicho, depende de lo que le exijan a cada uno y luego ya está el verano para aprender cosas nuevas. Esperemos que cuando lo lea Zeenek no se lie mucho. Saludos
19 respuestas