Verificar que se lee con fscanf

Iniciado por bastri, 9 Junio 2015, 08:06 AM

0 Miembros y 1 Visitante están viendo este tema.

bastri

Hola, tengo el siguiente codigo:
#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

ivancea96

Código (cpp) [Seleccionar]
http://www.cplusplus.com/reference/cstdio/scanf/

CitarIf 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.

rir3760

Cita de: bastri en  9 Junio 2015, 08:06 AMEl 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:
void leerarchivo(char *path)
{
   FILE *in;
   int rv;
   int num;

   if ((in = fopen(path, "r")) != NULL){
      while((rv = fscanf(in, "%d", &num)) != EOF){
         if (rv == 1)
            printf("Numero: %d\n", num);
         else {
            int ch;

            while ((ch = fgetc(in)) != EOF && !isdigit(ch))
               ;
            ungetc(ch, in);
         }
      }

      fclose(in);
   }
}


Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

bastri

#3
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?

rir3760

Cita de: bastri en 10 Junio 2015, 05:46 AM1- 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.


Cita de: bastri en 10 Junio 2015, 05:46 AM2- 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:
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.

Cita de: bastri en 10 Junio 2015, 05:46 AM3- 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
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language