Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: bastri en 9 Junio 2015, 08:06 am



Título: Verificar que se lee con fscanf
Publicado por: bastri en 9 Junio 2015, 08:06 am
Hola, tengo el siguiente codigo:
Código:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void leerarchivo(char path[]){
FILE *archivo;
int numero;

archivo = fopen(path, "r"); //

if (archivo != NULL){
while(!feof(archivo)){
fscanf(archivo, "%d\n", &numero);
printf("numero: %d\n", numero);
}
}
fclose(archivo);
}

int main(int argc, char** argv){
leerarchivo("archivo2");
return 0;
}

Basicamente lee numeros desde "archivo2" y los muestra uno abajo del otro.

El motivo de mi post radica en que si yo al archivo le pongo algun caracter se genera un bucle que muestra infinitas veces el ultimo numero. Y por ende yo quisiera que no lea los caracteres del archivo que no sean numeros para que esto no suceda.

Como puedo solucionarlo y porque pasa esto? Gracias de antemano


Título: Re: Verificar que se lee con fscanf
Publicado por: ivancea96 en 9 Junio 2015, 09:07 am
Código
  1. http://www.cplusplus.com/reference/cstdio/scanf/

Citar
If the character does not match, the function fails, returning and leaving subsequent characters of the stream unread.

Si encuentra un caracter que no cuadra con el formato eue le has pasado, no modificará el stream (el archivo al usar fsanf), y ferror() retornará un valor distinto de 0.

Puedes comprobar ferror() para saber si hay algún caracter erróneo. En cualquier caso, si hay caracteres aleatorios en el archivo, es difícil que lo puedas leer con el programa. El archivo ha de tener un formato lógico que tu programa pueda leer.


Título: Re: Verificar que se lee con fscanf
Publicado por: rir3760 en 9 Junio 2015, 17:29 pm
El motivo de mi post radica en que si yo al archivo le pongo algun caracter se genera un bucle que muestra infinitas veces el ultimo numero. Y por ende yo quisiera que no lea los caracteres del archivo que no sean numeros para que esto no suceda.

Como puedo solucionarlo y porque pasa esto? Gracias de antemano
Lo mejor por sencillo es seguir la recomendación de ivancea96.

Si aun así quieres leer los números en el archivo puedes utilizar:
* fscanf para leerlos.
* fgetc para leer y descartar los caracteres que no sean dígitos (isdigit).
* ungetc para retornar el ultimo carácter leído al stream.

De esta forma:
Código
  1. void leerarchivo(char *path)
  2. {
  3.   FILE *in;
  4.   int rv;
  5.   int num;
  6.  
  7.   if ((in = fopen(path, "r")) != NULL){
  8.      while((rv = fscanf(in, "%d", &num)) != EOF){
  9.         if (rv == 1)
  10.            printf("Numero: %d\n", num);
  11.         else {
  12.            int ch;
  13.  
  14.            while ((ch = fgetc(in)) != EOF && !isdigit(ch))
  15.               ;
  16.            ungetc(ch, in);
  17.         }
  18.      }
  19.  
  20.      fclose(in);
  21.   }
  22. }

Un saludo


Título: Re: Verificar que se lee con fscanf
Publicado por: bastri en 10 Junio 2015, 05:46 am
Muchas gracias a ambos. Me estoy metiendo de lleno en C y me alegra saber que hay gente del otro lado queriendote ayudar.

PD: Estoy analizando el codigo y hay dos dudas que se me generaron:

1- Al poner en el while "... && !isdigit(ch)..." estamos diciendo que el while de verdadero si isdigit retorna 0, no?

2- Porque se usa el ultimo while con ungetc? busque sobre esta funcion pero las explicaciones no las pude entender.

3- fscanf va a retornar algo diferente a 1 si por ej: le especificamos un solo %d y este dato no es un digito?


Título: Re: Verificar que se lee con fscanf
Publicado por: rir3760 en 11 Junio 2015, 17:04 pm
1- Al poner en el while "... && !isdigit(ch)..." estamos diciendo que el while de verdadero si isdigit retorna 0, no?
Correcto. El bucle se ejecutara mientras el carácter leído no sea EOF (error o fin de archivo) y no sea un dígito.


2- Porque se usa el ultimo while con ungetc? busque sobre esta funcion pero las explicaciones no las pude entender.
Porque el bucle puede terminar cuando se lee un digito. Por ejemplo supongamos que el contenido del archivo es:
Código:
jhgkhjgjklh123
Todos los caracteres para los cuales isdigit retorna cero (falso) se descartan mediante el mentado bucle, se lee el carácter '1' el cual es un dígito y causa la salida de este. El detalle es que ese carácter se debe procesar con los siguientes para forma el numero 123, eso se logra retornando el carácter '1' al stream mediante la función ungetc.

3- fscanf va a retornar algo diferente a 1 si por ej: le especificamos un solo %d y este dato no es un digito?
Si. Cuando se utiliza "%d" con fscanf los posibles valores de retorno son:

A) 1 si se lee con éxito el entero.
B) 0 si falla por un matching failure, por ejemplo la entrada es "JKL".
C) EOF si falla por un input failure, por ejemplo el gato destrozo el HD.

Un saludo