Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: Apazche en 27 Diciembre 2017, 00:39 am



Título: [Función fscanf]
Publicado por: Apazche en 27 Diciembre 2017, 00:39 am
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




Título: Re: [Función fscanf]
Publicado por: fary en 28 Diciembre 2017, 15:16 pm
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

Código
  1. #include <stdio.h>
  2.  
  3. int main()
  4. {
  5.    char JmpLine[2] = {0};
  6.  
  7.    JmpLine[0] = 10;
  8.    JmpLine[1] = 13;
  9.    JmpLine[2] = 0;
  10.  
  11.    printf("Una linea %s Otra linea",JmpLine);
  12.  
  13.    return 0;
  14. }

saludos y espero resolver tu duda.

saludos.


Título: Re: [Función fscanf]
Publicado por: MAFUS en 28 Diciembre 2017, 20:24 pm
El retorno de carro depende del sistema operativo:
*nix: '\n'
Windows: '\n''\r'
MacOS: '\r'


Título: Re: [Función fscanf]
Publicado por: dijsktra en 23 Abril 2018, 01:14 am
Código
  1.  


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
Código
  1. long ftell(FILE *stream)

pero que podemos simular con

Código
  1. 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.

Código
  1. #include <stdlib.h> // exit()...
  2. #include <assert.h> // assert
  3. #include <unistd.h> // open,read,close (Low-level IO),
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h> // open,O_RDONLY...
  7. #include <stdio.h> //p printf
  8.  
  9.  
  10. #include <ctype.h> // isprint
  11.  
  12. int main()
  13. {
  14.  char c;
  15.  int n;
  16.  int fd;
  17.  const char *pattern="%d\t%c\t%d\n";
  18.  char row[80];
  19.  if (!(fd=open("texto.txt",O_RDONLY)))
  20.    {
  21.      perror("open");
  22.      exit(EXIT_FAILURE);
  23.    }
  24.  printf("ASCII\tPrint\tPos\n");
  25.  while((n=read(fd,&c,sizeof(char)))> 0)
  26.    {
  27.      assert(isascii(c));
  28.      if ((n=sprintf(row,pattern,c,isprint(c)?c:' ',lseek(fd,0,SEEK_CUR)))<0)
  29. {
  30.  perror("sprintf");
  31.  exit(EXIT_FAILURE);
  32. }
  33.      printf(row);
  34.    }
  35.  if (n==-1)
  36.    {
  37.      perror("read");
  38.      exit(EXIT_FAILURE);
  39.    }
  40.  close(fd);
  41.  exit(EXIT_SUCCESS);
  42. }
  43.  

Pasándole el fichero de texto propuesto
Código:
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)

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


Título: Re: [Función fscanf]
Publicado por: dijsktra en 20 Junio 2018, 15:42 pm
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
Código
  1. long ftell(FILE *stream)

Esto no es así necesariamente. Me corrijo a mí mismo. En high-level contamos con
Código
  1. 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:

Código
  1. #include <stdlib.h> // exit()...
  2. #include <assert.h> // assert
  3. #include <stdio.h> //p printf
  4. #include <ctype.h> // isprint
  5.  
  6. int main()
  7. {
  8.  char c;
  9.  int n;
  10.  FILE* fs;
  11.  const char *pattern="%d\t%c\t%d\n";
  12.  char row[80];
  13.  if (!(fs=fopen("texto.txt","r")))
  14.    {
  15.      perror("fopen");
  16.      exit(EXIT_FAILURE);
  17.    }
  18.  printf("ASCII\tPrint\tPos\n");
  19.  while((c=fgetc(fs))!=EOF)
  20.    {
  21.      assert(isascii(c));
  22.      if ((n=sprintf(row,pattern,c,isprint(c)?c:' ',ftell(fs)))<0)
  23. {
  24.  perror("sprintf");
  25.  exit(EXIT_FAILURE);
  26. }
  27.      printf(row);
  28.    }
  29.  if (c!=EOF)
  30.    {
  31.      perror("fgetc");
  32.      exit(EXIT_FAILURE);
  33.    }
  34.  fclose(fs);
  35.  exit(EXIT_SUCCESS);
  36. }
  37.  

Y la salida, como en el caso anterior, leyendo "texto.txt", queda
Código
  1.  
  2. ASCII Print Pos
  3. 115 s 1
  4. 117 u 2
  5. 112 p 3
  6. 104 h 4
  7. 111 o 5
  8. 108 l 6
  9. 97 a 7
  10. 115 s 8
  11. 97 a 9
  12. 100 d 10
  13. 107 k 11
  14. 106 j 12
  15. 104 h 13
  16. 111 o 14
  17. 108 l 15
  18. 97 a 16
  19. 115 s 17
  20. 97 a 18
  21. 100 d 19
  22. 10 20
  23. 97 a 21
  24. 100 d 22
  25. 104 h 23
  26. 111 o 24
  27. 108 l 25
  28. 97 a 26
  29. 100 d 27
  30. 115 s 28
  31. 97 a 29
  32. 10 30