[Función fscanf]

Iniciado por Apazche, 27 Diciembre 2017, 00:39 AM

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

Apazche

Hola buenas, quiero saber la posición del cur de un archivo de texto a medida que leo caracteres con la función fscanf. Entonces, implemente lo siguiente ,en términos generales:

char c;
 
         
     while(!feof(fichero)){
        fscanf(fichero," %c",&c);
         printf("%c",c);
        printf("(%ld) ", ftell(fichero));
     }

En el archivo contiene los siguiente:

---------------------------------------------------------------------

supholasadkjholasad
adholadsa

---------------------------------------------------------------------

En el terminal se imprime:
---------------------------------------------------------------------

s(1) u(2) p(3) h(4) o(5) l(6) a(7) s(8) a(9) d(10) k(11) j(12) h(13) o(14) l(15) a(16) s(17) a(18) d(19) a(21) d(22) h(23) o(24) l(25) a(26) d(27) s(28) a(29) a(29)

---------------------------------------------------------------------

Mis preguntas son:
¿Por qué el carácter '\n' no lo imprime cuando lo lee?
El número 20 se lo salta al terminar de leer la primera línea, ¿Por qué?
fscanf lee '\n' ?  '\n' es un char, cierto?

Espero sus respuestas :D



fary

Antes de nada quiero que sepas que mi teoría esta basada en mi mis conocimientos y puede ser erronea la explicación que te voy a dar.

He estado mirando en la documentación y no he encontrado respuesta, solo puedo comentarte que si quieres trabajar mejor con el fichero crees un puntero a los datos y no los vayas leyendo poco a poco. Puede que las funciones que estás usando para leer el archivo caracter a caracter supriman  los saltos de línea.

Por otra parte quiero que sepas que '\n' no es un solo caracter... No te lo explico, te lo muestro  :P

#include <stdio.h>

int main()
{
   char JmpLine[2] = {0};

   JmpLine[0] = 10;
   JmpLine[1] = 13;
   JmpLine[2] = 0;

   printf("Una linea %s Otra linea",JmpLine);

   return 0;
}


saludos y espero resolver tu duda.

saludos.
Un byte a la izquierda.

MAFUS

El retorno de carro depende del sistema operativo:
*nix: '\n'
Windows: '\n''\r'
MacOS: '\r'

dijsktra

#3
Código (bash) [Seleccionar]
Cita de: Apazche en 27 Diciembre 2017, 00:39 AM


Mis preguntas son:
¿Por qué el carácter '\n' no lo imprime cuando lo lee?
El número 20 se lo salta al terminar de leer la primera línea, ¿Por qué?
fscanf lee '\n' ?  '\n' es un char, cierto?

Espero sus respuestas :D


Como dices, "\n" es un carácter, pero la directiva de matching "%c", según el manual, salta todos los caracteres "white-space", (entendiendo estos como el spacio, el tablador, el fin de línea... todos los que responden a isspace(int c) ).
Si te fijas en la salida , salta del 19 al 21...

Otra aspecto tiene que ver con printf. Propimaente hablando, el caracter '\n' no es carácter imprimible, segun (isprint(c)) ,  sino de control iscntrl(c). En el caso de "\n" dicen que "debe" hacer un scrolling de 1 y empezar en la primera columna, no que imprima propiamente un caracter...



Una solución pasa por dejar usar las rutinas "high-level IO", los streams, a las de "low-level IO", los "file descriptors".

El incoveniente es que perdemos la funcionalidad de la rutina

long ftell(FILE *stream)


pero que podemos simular con

pos=lseek(fd,0,SEEK_CUR)

Por supuesto, para dar una salida formateada, debo volver a las rutinas "high-level" IO, como printf... Pero es un problema aparte de el de lectura read



Hay otro error, que ya muestro corregido, relatio a la función feof()... Esta función sólo tiene valores coherentes después de haber invocado la correspondiente fscanf, es decir, no puede anticipar si la cabeza lectora ha llegafo a fin de fichero..



Ahí va mi propuesta.


#include <stdlib.h> // exit()...
#include <assert.h> // assert
#include <unistd.h> // open,read,close (Low-level IO),
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> // open,O_RDONLY...
#include <stdio.h> //p printf


#include <ctype.h> // isprint

int main()
{
 char c;
 int n;
 int fd;
 const char *pattern="%d\t%c\t%d\n";
 char row[80];
 if (!(fd=open("texto.txt",O_RDONLY)))
   {
     perror("open");
     exit(EXIT_FAILURE);
   }
 printf("ASCII\tPrint\tPos\n");
 while((n=read(fd,&c,sizeof(char)))> 0)
   {
     assert(isascii(c));
     if ((n=sprintf(row,pattern,c,isprint(c)?c:' ',lseek(fd,0,SEEK_CUR)))<0)
{
 perror("sprintf");
 exit(EXIT_FAILURE);
}
     printf(row);
   }
 if (n==-1)
   {
     perror("read");
     exit(EXIT_FAILURE);
   }
 close(fd);
 exit(EXIT_SUCCESS);
}


Pasándole el fichero de texto propuesto

supholasadkjholasad
adholadsa


El programa arroja la salida siguiente: Cuando es imprimible, imprime su símbolo, cuando es de control, en su lugar, un espacio. (Los números que salen al principio los pone el codgo GeSHi del web, porque si no, perdía el formato de salida... un lío vamos)



ASCII Print Pos
115 s 1
117 u 2
112 p 3
104 h 4
111 o 5
108 l 6
97 a 7
115 s 8
97 a 9
100 d 10
107 k 11
106 j 12
104 h 13
111 o 14
108 l 15
97 a 16
115 s 17
97 a 18
100 d 19
10 20
97 a 21
100 d 22
104 h 23
111 o 24
108 l 25
97 a 26
100 d 27
115 s 28
97 a 29
10 30
Si la depuración es el proceso de eliminar fallos en el software, entonces programar debe ser el proceso de ponerlos dentro. (Edsger Dijsktra)

dijsktra

Cita de: dijsktra en 23 Abril 2018, 01:14 AM
Una solución pasa por dejar usar las rutinas "high-level IO", los streams, a las de "low-level IO", los "file descriptors".

El incoveniente es que perdemos la funcionalidad de la rutina

long ftell(FILE *stream)


Esto no es así necesariamente. Me corrijo a mí mismo. En high-level contamos con

int fgetc(FILE *stream);


que, sin buscar patrones como scanf, hace lo que queremos, conservando el ftell
El erroes es que en vez de scanf , la rutina qie había que haber utilizado era
fgetc

El nuevo programa, más sencillo queda:


#include <stdlib.h> // exit()...
#include <assert.h> // assert
#include <stdio.h> //p printf
#include <ctype.h> // isprint

int main()
{
  char c;
  int n;
  FILE* fs;
  const char *pattern="%d\t%c\t%d\n";
  char row[80];
  if (!(fs=fopen("texto.txt","r")))
    {
      perror("fopen");
      exit(EXIT_FAILURE);
    }
  printf("ASCII\tPrint\tPos\n");
  while((c=fgetc(fs))!=EOF)
    {
      assert(isascii(c));
      if ((n=sprintf(row,pattern,c,isprint(c)?c:' ',ftell(fs)))<0)
{
  perror("sprintf");
  exit(EXIT_FAILURE);
}
      printf(row);
    }
  if (c!=EOF)
    {
      perror("fgetc");
      exit(EXIT_FAILURE);
    }
  fclose(fs);
  exit(EXIT_SUCCESS);
}


Y la salida, como en el caso anterior, leyendo "texto.txt", queda


ASCII Print Pos
115 s 1
117 u 2
112 p 3
104 h 4
111 o 5
108 l 6
97 a 7
115 s 8
97 a 9
100 d 10
107 k 11
106 j 12
104 h 13
111 o 14
108 l 15
97 a 16
115 s 17
97 a 18
100 d 19
10 20
97 a 21
100 d 22
104 h 23
111 o 24
108 l 25
97 a 26
100 d 27
115 s 28
97 a 29
10 30

Si la depuración es el proceso de eliminar fallos en el software, entonces programar debe ser el proceso de ponerlos dentro. (Edsger Dijsktra)