¿Cómo funciona scanf() en este programa?

Iniciado por alfred_oh, 21 Febrero 2014, 16:03 PM

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

alfred_oh

Hola tengo el siguiente programa en c y la verdad no me queda muy claro de que manera afecta scanf() al buffer de teclado.


#include <stdio.h>

int main(void){
   int a;
   int b;
   printf("ingrese el valor de a: \n");
fflush(stdin);
   scanf("%d",&a);
fflush(stdin);
   printf("ingrese el valor de b: \n");
   scanf("%d",&b);
fflush(stdin);
   printf("\n a= %d\n",a);
   printf("\n b= %d\n",b);
return 0;
}


Yo lo que quiero es que mi programa lea el valor de a y el valor b por separado y luego lo saque por pantalla. El problema era cuando introducía para "a" varios números separados por espacio y apretaba enter p.e.: "1 2 3 4 5 \n" me imprimía a=1 y b=2. Por ahí leí que esto era porque lo último que introduzco por el teclado es enter, por lo tanto esa tecla se queda almacenada allí, en el buffer ¿Eso es así? ¿De que manera influye el hecho de introducir enter en el buffer del teclado? Estuve investigando y leí que la solución era vaciar el buffer para esto utilice fflush() pero creo que no funciona para vaciar este tipo de buffer. Así que seguí buscando y sugerían en un foro(de hace unos años atrás) utilizar "while(getchar()!='\n');" Modifiqué mi código y quedó así:


int main(void){
   int a;
   int b;
   printf("ingrese el valor de a: \n");
   scanf("%d",&a);
while(getchar()!='\n');
   printf("ingrese el valor de b: \n");
   scanf("%d",&b);
   printf("\n a= %d\n",a);
   printf("\n b= %d\n",b);
return 0;
}

Ya no tenía este problema. Lo que pasa es que tampoco entiendo como "while(getchar()!='\n');" me ayuda. Lo que entiendo que hace esa línea es "sacar del buffer" todos los símbolos menos el "\n", luego el símbolo que queda en el buffer de teclado es "\n", entonces realmente no esta vacío no? Alguien puede explicármelo porfavor! Gracias!

J.cE

no entendi muy bien, el primer codigo que pusiste funciona bien, excepto por que me parece que el primer fflush(stdin); esta de mas.
fflush(stdin); sirve para borrar el bufer del teclado entonces cunado tu escribas 1 2 3 4 5, scanf solo tomara hasta el primer espacio y los demas numeros quedan guardados en el buffer, aqui es donde entra fflush(stdin); borrando el buffer y evitando que estos se almacenen en el siguiente scanf

#include <stdio.h>

int main(void)
{
int a;
int b;
printf("ingrese el valor de a: \n");
scanf("%d",&a);
fflush(stdin);//para vaciar el buffer del teclado
printf("ingrese el valor de b: \n");
scanf("%d",&b);
fflush(stdin);//para vaciar el buffer del teclado
printf("\n a= %d\n",a);
printf("\n b= %d\n",b);
return 0;
}

rir3760

Cita de: alfred_oh en 21 Febrero 2014, 16:03 PMtengo el siguiente programa en c
Lo primero que debes hacer es evitar el uso de fflush(stdin), las razones de ello en el tema |Lo que no hay que hacer en C/C++. Nivel basico|.

Al eliminarlo del programa tenemos:
#include <stdio.h>

int main(void)
{
   int a;
   int b;
   
   puts("Ingrese el valor de a:");
   scanf("%d", &a);

   puts("Ingrese el valor de b:");
   scanf("%d",&b);

   printf("a = %d\n", a);
   printf("b = %d\n", b);
   
   return 0;
}



Tomando ese programa como base ...


Cita de: alfred_oh en 21 Febrero 2014, 16:03 PMla verdad no me queda muy claro de que manera afecta scanf() al buffer de teclado.
Cuando utilizas scanf con el especificador "%d" lo que hace la funcion es:
1) Descarta el espacio blanco, por ello puedes introducir "       123" sin problemas.
2) Consume de la entrada estandar los caracteres que sean validos para la conversion en turno.
3) Al encontrar el primer caracter invalido (o una limitante en el especificador) ese caracter se queda intacto en la entrada estandar y se pasa a la siguiente conversion.

En tu programa si introduces:
    123    456{ENTER}
La primera llamada a scanf descarta el espacio blanco y consume los caracteres "123" para en base a ellos obtener el entero 123, el espacio inmediatamente despues del '3' causa el final de esa conversion y, al ser la ultima, el final de la llamada a scanf.

Para la segunda llamada a scanf el bufer de la entrada estandar contiene:
    456{ENTER}
Y la operacion es similar: scanf descarta los espacios, obtiene el entero  456 y el {ENTER} se queda en el bufer de la entrada estandar.

Cita de: alfred_oh en 21 Febrero 2014, 16:03 PMModifiqué mi código y quedó así:

...

while (getchar() != '\n')
   ;


...

Lo que pasa es que tampoco entiendo como "while(getchar()!='\n');" me ayuda. Lo que entiendo que hace esa línea es "sacar del buffer" todos los símbolos menos el "\n", luego el símbolo que queda en el buffer de teclado es "\n", entonces realmente no esta vacío no?
Por partes:

* Ese bucle descarta todos los caracteres incluyendo el '\n' ya que se puede leer como "Mientras el caracter leido NO sea '\n'" y, por supuesto, al leerlo se descarta.

* Como usualmente la entrada es por linea la intentencion de utilizar scanf y ese bucle es 1) Leer un entero con scanf y 2) Descartar el resto de la linea con el mentado bucle. Todo ello para evitar el comportamiento que mencionas.

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

alfred_oh

Muchas gracias por la explicación, sobre todo por la parte de "%d descarta los blancos". Con esa idea en la cabeza pude entenderlo fácilmente! Poniéndonos en otro situación, si por ejemplo introducimos:
" 123 {ENTER}"
En primer scanf lo que haría sería descartar el primer espacio y coger 123.
Luego el segundo scanf descartaría el segundo espacio, pero que hace con {ENTER}? Lo descarta también? Me imagino que si no? porque si no, no se quedaría esperando a que introduzcamos un número no? Entonces podríamos decir que %d descarta todo lo que no sea int?

PD: Gracias también por en enlace de "Lo que no hay que hacer en C/C++. Nivel basico"! Lo revisaré!

rir3760

Cita de: alfred_oh en 22 Febrero 2014, 10:15 AMPoniéndonos en otro situación, si por ejemplo introducimos:
" 123 {ENTER}"
En primer scanf lo que haría sería descartar el primer espacio y coger 123.
Luego el segundo scanf descartaría el segundo espacio, pero que hace con {ENTER}? Lo descarta también?
Si. Se descarta todo el espacio blanco antes de la conversión (espacio, tabulador, avance de linea, etc.).

Cita de: alfred_oh en 22 Febrero 2014, 10:15 AMEntonces podríamos decir que %d descarta todo lo que no sea int?
No porque eso puede llevar a confusiones. Es mejor decir que salvo "%c" y "%[]" con cualquier otro especificador (por ejemplo "%d", "%s", etc.) el espacio blanco al inicio no importa (ya que se descarta).

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

alfred_oh

#5
Gracias por la aclaración! ;) Aprovecho para preguntar si también sería necesario este vaciado de BUFFER DE ENTRADA tras usar gets(), este caso sería diferente pues gets() lee hasta el final, es decir, hasta encontrarse con el símbolo '\n' no? Luego no haría falta vaciado no?