elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: ¿Eres nuevo? ¿Tienes dudas acerca del funcionamiento de la comunidad? Lee las Reglas Generales


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  funcion limpiar buffer de teclado
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: funcion limpiar buffer de teclado  (Leído 8,631 veces)
Locura_23

Desconectado Desconectado

Mensajes: 162



Ver Perfil
funcion limpiar buffer de teclado
« en: 6 Octubre 2021, 16:51 pm »

Buenas a todos,

Tengo una duda con la siguiente función... la saqué de un libro de texto. Y es una solución para limpiar buffer de entrada de teclado (sin usar el vaciado de fflush() ) en C, antes de leer un string. Solo que cuando la utilizo en la consola, tengo que oprimir dos veces  salto de linea, una vez cuando ingreso el dato y otra vez mas para que salte de linea.  A diferencia de ingresar el dato y oprimir salto de linea "enter", y que se guarde el dato de inmediato.

Alguien sabe una alternativa a esta función ?

Saludos

Código
  1.  
  2. void limpiarBuffer()
  3. {
  4.    char c;
  5.  
  6.    do
  7.    {
  8.        c = getchar();
  9.    }while( c != '\n' );
  10.  
  11. }
  12.  
  13.  


« Última modificación: 6 Octubre 2021, 16:54 pm por Locura_23 » En línea

RayR

Desconectado Desconectado

Mensajes: 239


Ver Perfil
Re: funcion limpiar buffer de teclado
« Respuesta #1 en: 6 Octubre 2021, 17:56 pm »

Las formas estándar y portables de hacerlo son sólo variaciones de la que has puesto. En C++ puedes usar cin.ignore:

Código
  1. cin.ignore(tam, '\n');

que lee y descarta hasta "tam" caracteres o hasta encontrar un '\n'. Puedes usar un número muy grande para tam, o bien, numeric_limits<streamsize>::max(), que es el tamaño máximo de un stream:

Código
  1. #include <limits>
  2. ...
  3. cin.ignore(numeric_limits<streamsize>::max(), '\n');

que básicamente significa que limpie todo lo que haya, hasta que encuentre el caracter de línea nueva. Hay alguna otra manera pero a final de cuentas, como te dije, son variaciones de esto.

Eso sí, evita fflush(stdin), que es directamente erróneo aunque a veces funcione. Otra solución que a veces se lee es mediante fseek, pera tampoco deberías usarla. Entre otras cosas no es portable y no hay ni siquiera garantía de que siga funcionando en las plataformas donde actualmente lo hace.

Lo del doble Enter no debería ser necesario. Creo que sé dónde está tu error, pero sería mejor su pusieras un código de ejemplo donde pase.


En línea

MAFUS


Desconectado Desconectado

Mensajes: 1.603



Ver Perfil
Re: funcion limpiar buffer de teclado
« Respuesta #2 en: 6 Octubre 2021, 18:19 pm »

Bueno, ahí va un hack que me ha funcionado siempre:

Código:
fseek(stdin, 0, SEEK_END);
En línea

Locura_23

Desconectado Desconectado

Mensajes: 162



Ver Perfil
Re: funcion limpiar buffer de teclado
« Respuesta #3 en: 6 Octubre 2021, 20:26 pm »

Bueno, ahí va un hack que me ha funcionado siempre:

Código:
fseek(stdin, 0, SEEK_END);

Hola MAFUS, funciona bien ese hack xD gracias!

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

RayR gracias por tu aporte !

El tema es que solo uso C en este programa, tengo entendido que no es buena práctica combinar las cosas no?

Por alguna razón, en el momento de publicar la pregunta eso me pasaba (del doble enter) y me ha pasado en otros programas donde incluí esta función que mencioné. Aveces pasa y aveces no, es raro... acá dejo donde la estaba usando en este caso.

Código
  1.  
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <sysinfoapi.h>
  5.  
  6. typedef struct
  7. {
  8.    char nombreDragon[30];
  9.    int numeroClase;
  10.    char color[15];
  11.    int puntaje;
  12.    int mes;
  13.    int dia;
  14. }dragon;
  15.  
  16. void limpiarBuffer()
  17. {
  18.    char c;
  19.  
  20.    do
  21.    {
  22.        c = getchar();
  23.    }while( c != '\n' );
  24.  
  25. } // fin funcion
  26.  
  27. dragon cargarDatosDragon()
  28. {
  29.    dragon aux;
  30.    SYSTEMTIME datosTiempo;
  31.  
  32.    printf("\n<< Carga de datos >>\n");
  33.  
  34.    printf("\nIngrese el nombre del dragon >> ");
  35.    limpiarBuffer();
  36.    gets(aux.nombreDragon);
  37.  
  38.    printf("\nIngrese el numero de clase >> ");
  39.    scanf("%d",&aux.numeroClase);
  40.  
  41.    printf("\nIngrese el color >> ");
  42.    limpiarBuffer();
  43.    gets(aux.color);
  44.  
  45.    printf("\nIngrese el puntaje >> ");
  46.    scanf("%d",&aux.puntaje);
  47.  
  48.    GetLocalTime(&datosTiempo);
  49.  
  50.    aux.mes = datosTiempo.wMonth;
  51.    aux.dia = datosTiempo.wDay;
  52.  
  53.    return aux;
  54.  
  55. } // fin funcion
  56.  
  57. int main()
  58. {
  59.    dragon nuevoDragon;
  60.  
  61.    nuevoDragon = cargarDatosDragon();
  62.  
  63.    return 0;
  64.  
  65. } // fin main
  66.  
  67.  

pd: ignorese los gets() y demas cosas mejorables, es solo un boceto jaja

« Última modificación: 6 Octubre 2021, 20:28 pm por Locura_23 » En línea

MAFUS


Desconectado Desconectado

Mensajes: 1.603



Ver Perfil
Re: funcion limpiar buffer de teclado
« Respuesta #4 en: 6 Octubre 2021, 20:51 pm »

El problema con esa función es que si el buffer ya está vacío getchar tomará el control de la consola obligando a que el buffer se llene otra vez. Es decir: esa función sólo hace el trabajo esperado si en el buffer quedó algo.
En línea

Locura_23

Desconectado Desconectado

Mensajes: 162



Ver Perfil
Re: funcion limpiar buffer de teclado
« Respuesta #5 en: 6 Octubre 2021, 21:10 pm »

El problema con esa función es que si el buffer ya está vacío getchar tomará el control de la consola obligando a que el buffer se llene otra vez. Es decir: esa función sólo hace el trabajo esperado si en el buffer quedó algo.

mm ya veo, tiene total sentido eso que decis. De ahi que aveces me haga eso y otras no
En línea

RayR

Desconectado Desconectado

Mensajes: 239


Ver Perfil
Re: funcion limpiar buffer de teclado
« Respuesta #6 en: 6 Octubre 2021, 21:34 pm »

La clave es limpiar el buffer sólo cuando sabes que no está vacío. ¿Cómo puedes saber esto? Depende, pero de forma muy general, cuando lees, por ejemplo, enteros y flotantes, scanf siempre deja el '\n' en el buffer, por lo que necesitas limpiarlo si la siguiente instrucción de entrada lee caracteres o cadenas. La función gets quita el '\n', así que no tienes que limpiarlo después de llamarla. Si lo haces, se producirá  el mismo problema de tener que introducir dos veces el salto de línea. Si usas fgets, la cosa cambia, pero eso lo puedes consultar en la documentación de esa función en cualquier manual.

P.D. La razón por la que te mencioné que no te aconsejaba la solución con fseek es que, por ejemplo, no funciona en Linux. Esto no es falla del SO, sino que en realidad los "streams", cuando no están asociados a un archivo real, no tienen por qué admitir búsquedas. La entrada estándar del teclado no es un archivo normal, así que puede o no admitirlas. En Windows funciona (por ahora) pero no es seguro saber si siempre lo hará. Esto no es meramente teórico; la propia fflush(stdin) funcionaba antes en Visual C++, y de hecho, la documentación oficial de Microsoft así lo especificaba, y sin embargo, hace unos años eliminaron esa funcionalidad y ya no funciona ni se menciona en la documentación actual. Así que la solución del fseek perfectamente podría dejar de funcionar en la siguiente actualización (o no, quién sabe) sin previo aviso. De cualquier manera, puesto que la manera estándar (como tu función) es tan simple, portable, y su funcionamiento está garantizado, no le veo sentido a usar una que no cumple con estas ventajas. En todo caso, si de todas maneras la quieres usar, deberías considerarla como a gets (algo temporal que igual vale para ejercicios de práctica, pero nada más). Y recomiendo checar esto: https://blog.codinghorror.com/the-works-on-my-machine-certification-program/

Algunas referencias sobre las búsquedas en stdin, por si te interesa.Para mi gusto las explicaciones están algo incompletas, y hay aún más razones para evitarlo, pero no están mal (en particular, la respuesta aceptada del primer linky sus comentarios):

https://stackoverflow.com/questions/16672672/can-fseekstdin-1-seek-set-or-rewindstdin-be-used-to-flush-the-input-buffer-i
https://stackoverflow.com/questions/4917801/using-fseek-with-a-file-pointer-that-points-to-stdin
En línea

Locura_23

Desconectado Desconectado

Mensajes: 162



Ver Perfil
Re: funcion limpiar buffer de teclado
« Respuesta #7 en: 15 Octubre 2021, 21:36 pm »

Siento revivir el tema, pero si alguna vez alguien necesita saber sobre esto, acá dejo otro hack que encontré recién, sirve para leer con la función scanf(), manteniendo limpio el buffer.

Código
  1. /**Muestra como leer un dato con scanf, de manera que el buffer quede limpio despues de la
  2. lectura, no es necesario utilizar el fflush**/
  3.  
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6.  
  7. int main()
  8. {
  9.    int num = 0;
  10.    char palabra[15] = {""};
  11.  
  12.    printf("Ingrese un numero.\n");
  13.    scanf("%i%*c",&num); ///hack
  14.  
  15.    printf("El numero ingresado fue: %i\n",num);
  16.  
  17.    printf("\n\nIngrese una palabra.\n");
  18.    gets(palabra);
  19.  
  20.    printf("\nLa palabra ingresada fue: %s\n",palabra);
  21.  
  22.    return 0;
  23. }
  24.  

prueba de que funciona es que tras ingresar el numero entero se puede leer tranquilamente un string.
« Última modificación: 15 Octubre 2021, 21:40 pm por Locura_23 » En línea

RayR

Desconectado Desconectado

Mensajes: 239


Ver Perfil
Re: funcion limpiar buffer de teclado
« Respuesta #8 en: 15 Octubre 2021, 23:57 pm »

Pero eso no deja limpio el buffer. Simplemente lee un caracter, justo como si pusieras un "%c" (o un único getchar() después del scanf). El * hace que no lo asigne a una variable, pero por lo demás, no hay mayor diferencia. Sí te sirve suponiendo que siempre introduzcas puros dígitos, pero si, por error (o no) introduces algo como "15 ", o sea, el número con un espacio (o cualquier otro caracter) al final, vas a volver a tener el mismo problema, lo cual no pasa cuando limpias el buffer, por ejemplo con la función que pusiste en el mensaje original.

Hay formas más complejas de scanf que sí pueden limpiarlo (puedes googlear el especificador '[' ), pero tienen sus inconvenientes, por lo que, en mi opinión no valen la pena para este propósito.
En línea

Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
Limpiar teclado del portatil
Hardware
Gambinoh 6 5,439 Último mensaje 22 Abril 2011, 18:42 pm
por Gambinoh
Limpiar Buffer en Linux (estructuras)
Programación C/C++
dalberto9410 7 5,195 Último mensaje 26 Marzo 2013, 17:25 pm
por dalberto9410
Limpieza de buffer de teclado en lenguaje C. « 1 2 »
Programación C/C++
NOB2014 16 10,584 Último mensaje 20 Enero 2014, 23:37 pm
por leosansan
Como limpiar el teclado de una laptop
Hardware
PC Tips 3 2,662 Último mensaje 27 Octubre 2014, 21:30 pm
por Randomize
TIP: para limpiar el buffer de entrada
Programación C/C++
MAFUS 4 5,886 Último mensaje 29 Abril 2016, 19:33 pm
por HardForo
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines