Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: apoeti en 9 Agosto 2012, 16:40 pm



Título: Duda gets()
Publicado por: apoeti en 9 Agosto 2012, 16:40 pm
Estudiando el libro de "Aprenda C en 21 días" me ha surgido una duda en el día 14. El libro platea un programa que usa scanf() y gets() para limpiar el buffer de teclado.
Para plantear mi duda dejo el código fuente:
Código:
/* Limpieza de caracteres adicionales de stdin. */

#include <stdio.h>

void clear_kb(void);

main()
{
      int age;
      char name[20];
     
      /* Pide la edad del usuario. */
     
      puts("Enter your age.");
      scanf("%d", &age);
     
      /* Limpia a stdin de cualquier carácter adicional. */
     
      clear_kb();
     
      /* Pide ahora el nombre del usuario. */
     
      puts("Enter your first name.");
      scanf("%s", name);
      /* Display the data. */
     
      printf("Your age is %d.\n", age);
      printf("Your name is %s.\n", name);
}

void clear_kb(void)

/* Limpia a stdin de cualquier carácter que esté en espera. */
{
          char junk[80];
          gets(junk);
}

El código es muy sencillito y entiendo lo que hace, pero me surge una duda con la función clear_kb. La duda es que por qué si normalmente cuando se llama a gets(), esta función recoge carácteres hasta que encuentra un retorno de carro, en este caso la función no espera la entrada de carácteres. Entiendo que no lo haga cuándo limpia el buffer del teclado, pues para eso está, pero lo que no entiendo es: ¿Por qué la función no espera la entrada de carácteres cuando el buffer de teclado está limpio?

Espero respuestas. Espero haberme explicado en condiciones.
Gracias de antemano.


Título: Re: Duda gets()
Publicado por: durasno en 10 Agosto 2012, 05:36 am
Citar
esta función recoge carácteres hasta que encuentra un retorno de carro
lee hasta encontrar un salto de linea

Citar
¿Por qué la función no espera la entrada de carácteres cuando el buffer de teclado está limpio?
no entiendo a q te referis. En el programa que pusiste siempre el bufer va a estar "sucio"(debido al caracter ENTER que deja scanf en el bufer del teclado), por lo tanto gets no espera la entrada de caracteres


Saludos


Título: Re: Duda gets()
Publicado por: xiruko en 10 Agosto 2012, 06:36 am
cuando usas scanf para leer un entero, esta funcion lee hasta el ultimo digito que encuentra y luego deja todo lo demas en el buffer de entrada. por ejemplo, si yo introdujera los siguientes caracteres cuando lo pidiera el scanf:

123fg45'\n' ('\n' ya que picas enter para introducir los datos y tambien se almacena en el bufer)

el scanf() leeria 123, y dejaria fg45'\n' en el buffer de entrada. esto es asi por propia definicion de la funcion scanf(). si quieres prueba este ejemplo y compruebalo por ti mismo:

Código
  1. #include <stdio.h>
  2. int main() {
  3. int a;
  4. char b[50];
  5. scanf("%d", &a);
  6.        //limpiarstdin();
  7. fgets(b, 49, stdin);
  8. printf("%d\n", a);
  9. printf("%s", b);
  10. return 0;
  11. }

sabiendo esto, puedes tambien comprobar que cuando usas gets(), esta lee en el bufer de entrada y ahi si que hay el caracter '\n', por lo que no te dara opcion a introducir nada y se recogera la basura que habia quedado en el bufer tras el scanf() hasta el caracter de nueva linea.

por cierto, esa funcion para eliminar la basura esta bien, aunque no limpiara del todo el bufer cuando haya una larga cola de basura (en tu caso, mayor a 80 caracteres). una alternativa es usar la siguiente funcion:

Código
  1. void limpiarstdin() {
  2. char a;
  3. while (a=getchar() != '\n');
  4. }

la cual si que limpiara del todo sea cual sea la longitud de basura.

un saludo!


Título: Re: Duda gets()
Publicado por: apoeti en 10 Agosto 2012, 16:23 pm
Muchas gracias a los dos por las respuestas. Creo que me ha quedado claro, pero por si acaso, pregunto. Según lo que me habéis dicho, el scanf(), no recoge el '\n' y siempre lo deja en el teclado ¿Es eso cierto?


Título: Re: Duda gets()
Publicado por: rir3760 en 10 Agosto 2012, 18:27 pm
En mi opinión un buen libro sobre C no debería tener ese tipo de ejemplos. No se recomienda el uso de la función "gets", la razón de ello se encuentra en uno de los temas fijos en el foro. Mismo caso con la función "scanf" cuando se utiliza en la forma:
Código
  1. char name[20];
  2.  
  3. /* ... */
  4.  
  5. puts("Enter your first name.");
  6. scanf("%s", name);
Ya que el riesgo es el mismo: no hay forma de limitar el numero de caracteres que se almacenan a partir de la dirección indicada.

Según lo que me habéis dicho, el scanf(), no recoge el '\n' y siempre lo deja en el teclado ¿Es eso cierto?
Usualmente si.

Una respuesta mejor es: depende del especificador de formato (por ejemplo "%d", "%s", etc.) utilizado.

Con todos ellos (salvo "%c" y "%[]") lo primero que hace la función es descartar el espacio blanco (espacio, tabulador, etc.). A continuación la función consume todos los caracteres que cumplan con el especificador (como ya te comento xiruko ), eso continua hasta cumplir con lo indicado o se encuentre un carácter invalido (el cual se queda en el bufer de la entrada estándar).

Un ejemplo de esto ultimo, una forma mas segura es:
Código
  1. char name[20];
  2.  
  3. /* ... */
  4.  
  5. puts("Enter your first name.");
  6. scanf("%19s", name);
Así la función descarta el espacio blanco, lee y almacena los caracteres (una palabra) en el array (máximo 19). Por ultimo almacena el '\0'.

Un saludo


Título: Re: Duda gets()
Publicado por: apoeti en 11 Agosto 2012, 14:25 pm
Muchas gracias, ya me ha quedado claro.