Foros del Web » Programación para mayores de 30 ;) » C/C++ »

Cómo evitar que el 'scanf' lea los datos introducidos antes?

Estas en el tema de Cómo evitar que el 'scanf' lea los datos introducidos antes? en el foro de C/C++ en Foros del Web. Hola a todos. Me explico: Llevo varios días intentando depurar un programa que me da infinidad de errores, la mayoría de los cuales he llegado ...
  #1 (permalink)  
Antiguo 29/05/2012, 03:23
 
Fecha de Ingreso: mayo-2012
Mensajes: 7
Antigüedad: 12 años, 5 meses
Puntos: 0
Cómo evitar que el 'scanf' lea los datos introducidos antes?

Hola a todos. Me explico: Llevo varios días intentando depurar un programa que me da infinidad de errores, la mayoría de los cuales he llegado a la conclusión que se producen por que el 'scanf' me lee datos introducidos anteriormente. Ejemplo:

Código C++:
Ver original
  1. do{
  2.         accion == ' ';
  3.  
  4.         if (accion == 'e' || accion == 'E'){
  5.  
  6.             accion == ' ';
  7.             entrar_vehiculo();
  8.  
  9.         } else if (accion == 's' || accion == 'S'){
  10.  
  11.             accion == ' ';
  12.             salir_vehiculo();
  13.         }
  14.        
  15.         printf("\nIndique acción a realizar (Si entra vehiculo pulse 'E', si sale vehiculo pulse 'S' si desea finalizar el programa pulse 'F'): ");
  16.         scanf("%c", &accion);
  17.  
  18.     } while (accion!= 'f' && accion != 'F');

La primera vez el bucle funciona correctamente, pero las siguientes el 'printf' se me repite dos y hasta tres veces porque, creo, el 'scanf' lee datos "residuales" que he introducido para otras funciones del programa en lugar de esperar a que introduzca nuevos datos, de manera que el bucle da una vuelta sin realizar ninguna acción y vuelve a introducir el texto. Creo que es un error básico, pero no he encontrado solución clara. Agradeceré cualquier aportación.
  #2 (permalink)  
Antiguo 29/05/2012, 03:52
 
Fecha de Ingreso: junio-2010
Ubicación: Madrid
Mensajes: 620
Antigüedad: 14 años, 5 meses
Puntos: 73
Respuesta: Cómo evitar que el 'scanf' lea los datos introducidos antes?

Ocurre que accion la lees al final del bucle do, mientras que al principio de este bucle haces accion = ' ', con lo cual, introduzcas lo que introduzcas, accion va a valer ' ' de cara a las comparaciones que estás haciendo. La solución es pedir accion al principio del bucle.
  #3 (permalink)  
Antiguo 29/05/2012, 05:17
 
Fecha de Ingreso: abril-2010
Ubicación: Rosario
Mensajes: 1.850
Antigüedad: 14 años, 7 meses
Puntos: 228
Respuesta: Cómo evitar que el 'scanf' lea los datos introducidos antes?

Que es lo que ocurre en tu programa? Si imprime varias veces en pantalla lo que esta en el printf??
  #4 (permalink)  
Antiguo 29/05/2012, 05:24
 
Fecha de Ingreso: mayo-2012
Mensajes: 7
Antigüedad: 12 años, 5 meses
Puntos: 0
Respuesta: Cómo evitar que el 'scanf' lea los datos introducidos antes?

Cita:
Iniciado por Fw190 Ver Mensaje
Ocurre que accion la lees al final del bucle do, mientras que al principio de este bucle haces accion = ' ', con lo cual, introduzcas lo que introduzcas, accion va a valer ' ' de cara a las comparaciones que estás haciendo. La solución es pedir accion al principio del bucle.
No, ese no es el problema, ya que el 'acción==0' no es una asignación, de hecho está ahí por error, pero no modifica el programa.

El 'scanf' está al final del do por que de tanto marearlo se ha quedado ahí, pero al principio lo tenía arriba y el resultado no cambia, pues el problema es que en 'accion' me carga datos que he introducido en los subprogramas en lugar de los que voy a introducir.

Me he acabado apañando con un rudimentario 'if' en el 'printf' que no me evita que el 'scanf' me lea los datos residuales, pero si evita que se imprima en pantalla el primer bucle, así me ha quedado:

Código C++:
Ver original
  1. int main (){
  2.  
  3.     char accion = ' ';
  4.  
  5.     do{
  6.  
  7.         if (accion == 'e' || accion == 'E'){
  8.  
  9.             entrar_vehiculo();
  10.  
  11.         } else if (accion == 's' || accion == 'S'){
  12.  
  13.             salir_vehiculo();
  14.  
  15.         } else if(accion == 'o' || accion == 'O'){
  16.  
  17.             printf("\n\n");
  18.             imprimir_parking();
  19.  
  20.         }
  21.  
  22.         if(accion != 'e' && accion != 'E' && accion != 's' && accion != 'S' && accion != 'o' && accion != 'O' && accion != 'F' && accion != 'f' ){
  23.             printf("\nIndique acción a realizar (Si entra vehiculo pulse 'E', si sale vehiculo pulse 'S', si desea observar el estado del parking pulse 'O', si desea finalizar el programa pulse 'F'): ");
  24.         }
  25.  
  26.         scanf("%c", &accion);
  27.  
  28.     } while (accion!= 'f' && accion != 'F');
  29.  
  30.     return 0;
  31. }

En otro foro me han dado una solución mejor que directamente limpia los datos de manera que el programa solo escanee una vez:

Código C++:
Ver original
  1. ...
  2.  
  3. flush_stdin()
  4. {
  5.    int ch;
  6.    while( (ch = getchar()) != '\n' && ch != EOF );
  7. }
  8.  
  9. ...
  10.  
  11.    scanf("%d", &a );
  12.    flush_stdin();
  13. ...
  14.    scanf("%d", &b );
  15.    flush_stdin();
  16. ...

Gracias.
  #5 (permalink)  
Antiguo 29/05/2012, 05:28
 
Fecha de Ingreso: mayo-2012
Mensajes: 7
Antigüedad: 12 años, 5 meses
Puntos: 0
Respuesta: Cómo evitar que el 'scanf' lea los datos introducidos antes?

Cita:
Iniciado por sam90 Ver Mensaje
Que es lo que ocurre en tu programa? Si imprime varias veces en pantalla lo que esta en el printf??
Si, eso es lo que ocurría. La primera vez no, pero las siguientes me hace un ciclo del 'do while' antes de que se pare a esperar que yo introduzca datos, por lo que me imprimía la pregunta dos veces. Con el 'if' que he añadido me sigue haciendo un primer ciclo del bucle antes de parar, pero evito que se imprima la pregunta en ese primer ciclo.

No se si me explico bien, soy noob..
  #6 (permalink)  
Antiguo 29/05/2012, 06:23
 
Fecha de Ingreso: abril-2010
Ubicación: Rosario
Mensajes: 1.850
Antigüedad: 14 años, 7 meses
Puntos: 228
Respuesta: Cómo evitar que el 'scanf' lea los datos introducidos antes?

La solucion que te dieron en el otro foro es la que yo te hubiese dado... el tema esta que cuando introduces una tecla y presionas enter el enter tambien se envia como un caracter. Entonces primero lees la letra hace la accion luego lees el enter que no coincide con ninguno de eso caracteres. Y ahi recien te da la posibilidad de empezar de nuevo.

La funcion flush_stdin() lo que hace es consumir las entradas por teclado hasta que encuentre un salto de linea (enter).

saludos
  #7 (permalink)  
Antiguo 29/05/2012, 07:48
 
Fecha de Ingreso: diciembre-2008
Mensajes: 50
Antigüedad: 15 años, 11 meses
Puntos: 0
Respuesta: Cómo evitar que el 'scanf' lea los datos introducidos antes?

Cita:
Iniciado por sam90 Ver Mensaje
La solucion que te dieron en el otro foro es la que yo te hubiese dado... el tema esta que cuando introduces una tecla y presionas enter el enter tambien se envia como un caracter. Entonces primero lees la letra hace la accion luego lees el enter que no coincide con ninguno de eso caracteres. Y ahi recien te da la posibilidad de empezar de nuevo.

La funcion flush_stdin() lo que hace es consumir las entradas por teclado hasta que encuentre un salto de linea (enter).

saludos
Yo lo suelo agregando un getchar() después de cada scanf y listo. Con eso se come el salto de línea en cuestión y no da problemas.... aunque claro, la función esa supongo que evita que el usurio se ponga a meter datos como loco y luego desajusten todo el programa jaja
  #8 (permalink)  
Antiguo 29/05/2012, 07:54
 
Fecha de Ingreso: mayo-2012
Mensajes: 7
Antigüedad: 12 años, 5 meses
Puntos: 0
Respuesta: Cómo evitar que el 'scanf' lea los datos introducidos antes?

Cita:
Iniciado por Javieer-G Ver Mensaje
aunque claro, la función esa supongo que evita que el usurio se ponga a meter datos como loco y luego desajusten todo el programa jaja
Sí, por lo visto si introduzco 20 caracteres en el 'scanf' anterior me formula la pregunta 20 veces, esto evitará que ocurra, ¿no es así?

Aunque no entiendo el significado de ch != EOF ..
  #9 (permalink)  
Antiguo 29/05/2012, 07:58
 
Fecha de Ingreso: diciembre-2008
Mensajes: 50
Antigüedad: 15 años, 11 meses
Puntos: 0
Respuesta: Cómo evitar que el 'scanf' lea los datos introducidos antes?

No me he mirado tu programa, pero el EOF es la marca de fin de fichero (End Of File). A nivel práctico, cuando pulsas Ctrl+Z en el terminal es como si metieras la marca EOF.
  #10 (permalink)  
Antiguo 29/05/2012, 12:41
Avatar de L3m0n  
Fecha de Ingreso: diciembre-2011
Mensajes: 219
Antigüedad: 12 años, 10 meses
Puntos: 46
Respuesta: Cómo evitar que el 'scanf' lea los datos introducidos antes?

En otro foro te han dado una muy buena solucion.

En ese codigo se crea una funcion que sustituye a la que mucha gente usa en windows, el fflush_stdin() que es un gran error, ya que no es portable.

Básicamente lo que hace la funcion que has puesto es vaciar el buffer de entrada
(lee caracteres hasta encontrarse con un '\n' (un enter) o un EOF(end of file))

Espero haberme explicado bien :)
  #11 (permalink)  
Antiguo 29/05/2012, 13:10
 
Fecha de Ingreso: mayo-2012
Mensajes: 2
Antigüedad: 12 años, 5 meses
Puntos: 0
Respuesta: Cómo evitar que el 'scanf' lea los datos introducidos antes?

tendria que ser accion=' '
  #12 (permalink)  
Antiguo 30/05/2012, 03:20
 
Fecha de Ingreso: mayo-2012
Mensajes: 7
Antigüedad: 12 años, 5 meses
Puntos: 0
Respuesta: Cómo evitar que el 'scanf' lea los datos introducidos antes?

Va como un tiro con el flush_stdin() :)

Aquí os dejo el programa completo y perfectamente depurado para quien le pueda interesar:

Código C++:
Ver original
  1. /***********************************************************************************************************************************************
  2.  
  3. PARKING:
  4.  
  5. Realizar un programa para controlar un aparcamiento que dispone de 25 plazas de 2 tamaños: 10 grandes y 15 pequeñas. Las plazas se asignaran
  6. automáticamente cuando entre un vehiculo segun el tamaño:
  7.  
  8. · Cada vehiculo solo ocupara una plaza.
  9. · Un vehiculo pequeño siempre ocupara una plaza pequeña salvo que estén todas ocupadas y haya plazas grandes libres.
  10. · Un vehiculo grande solo podrá aparcar en una plaza grande.
  11. · Cuando entre un vehiculo ocupara siempre la plaza de número menor de todas las libres.
  12.  
  13. El programa tendrá tres opciones básicas:
  14.  
  15. · Entrada: es necesario indicar el tamaño del coche.
  16. · Salida: es necesario indicar la plaza que deja libre.
  17. · Situación del aparcamiento: indicando las plazas libres y las ocupadas.
  18.  
  19. ***********************************************************************************************************************************************/
  20.  
  21. #include <stdio.h>
  22. #include <ctype.h>
  23.  
  24. /* Vectores que indicarán la situación de cada aparcamiento */
  25.  
  26. typedef bool Tipo_Vector_ParkingP[15];
  27. typedef bool Tipo_Vector_ParkingG[10];
  28. Tipo_Vector_ParkingP Vector_ParkingP = {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false};
  29. Tipo_Vector_ParkingG Vector_ParkingG = {false, false, false, false, false, false, false, false, false, false};
  30.  
  31. /* Función para limpiar el BUFFER */
  32.  
  33. void flush_stdin(){
  34.  
  35.    int ch;
  36.    while( (ch = getchar()) != '\n' && ch != EOF );
  37.  
  38. }
  39.  
  40. /* Subprograma que se encarga de imprimir las plazas pequeñas del parking una a una, vacias o llenas, según la situación del vector 'Vector_ParkingP' */
  41.  
  42. void imprimir_plazaP(){
  43.  
  44.     for(int k = 1; k <= 15; k++){
  45.  
  46.         if (Vector_ParkingP[k]){
  47.             printf("xx|");
  48.         } else {
  49.             printf("  |");
  50.         }
  51.     }
  52. }
  53.  
  54. /* Subprograma que se encarga de imprimir las plazas grandes del parking una a una, vacias o llenas, según la situación del vector 'Vector_ParkingG' */
  55.  
  56. void imprimir_plazaG(){
  57.  
  58.     for(int k = 1; k <= 10; k++){
  59.  
  60.         if (Vector_ParkingG[k]){
  61.             printf("xxx|");
  62.         } else {
  63.             printf("   |");
  64.         }
  65.     }
  66. }
  67.  
  68. /* Subprograma que imprime la gráfica del parking indicando su situación */
  69.  
  70. void imprimir_parking(){
  71.  
  72.     printf("   _01_02_03_04_05_06_07_08_09_10_11_12_13_14_15_\n");
  73.     printf("P >|");
  74.     imprimir_plazaP();
  75.     printf("\n   |");
  76.     imprimir_plazaP();
  77.     printf("\n   |                                            |\n");
  78.     printf("   |- - - - - - - - - - - - - - - - - - - -     |\n");
  79.     printf("   |                                            |\n");
  80.     printf("   |");
  81.     imprimir_plazaG();
  82.     printf("    |\nG >|");
  83.     imprimir_plazaG();
  84.     printf("in/ |\n   |___|___|___|___|___|___|___|___|___|___| out|\n");
  85.     printf("    01  02  03  04  05  06  07  08  09  10 |    |\n");
  86.  
  87. }
  88.  
  89. /* Subprograma que gestiona las entradas de vehiculos. */
  90.  
  91. void entrar_vehiculo(){
  92.  
  93.     char tecla = ' ';
  94.  
  95.     while (tecla != 'P' && tecla != 'G'){
  96.  
  97.         printf("\nIndique si el vehiculo es grande 'G' o pequeño 'P': ");
  98.  
  99.         scanf("%c", &tecla);
  100.         flush_stdin();
  101.         tecla = toupper (tecla);
  102.  
  103.         if(tecla != 'P' && tecla != 'G'){
  104.             printf("\nCOMANDO INCORRECTO\n");
  105.         }
  106.     }
  107.  
  108.     if (tecla == 'P'){
  109.  
  110.         for(int k = 1; k <= 15; k++){
  111.  
  112.             tecla = 'G';
  113.  
  114.             if (!Vector_ParkingP[k]){
  115.                 Vector_ParkingP[k] = true;
  116.                 tecla = ' ';
  117.                 k = 16;
  118.             }
  119.         }
  120.     }
  121.  
  122.     if (tecla == 'G'){
  123.  
  124.         for(int k = 1; k <= 10; k++){
  125.  
  126.             if (!Vector_ParkingG[k]){
  127.                 Vector_ParkingG[k] = true;
  128.                 k = 11;
  129.                 tecla = ' ';
  130.             }
  131.         }
  132.     }
  133.  
  134.     if (tecla != ' '){
  135.  
  136.         printf("\n\nParking lleno, no pueden entrar más vehiculos:\n\n");
  137.  
  138.     } else {
  139.  
  140.         printf("\n\nEl vehiculo ha ocupado su plaza:\n\n");
  141.         tecla = ' ';
  142.     }
  143.  
  144.     imprimir_parking();
  145. }
  146.  
  147. /* Subprograma que gestiona las salidas de vehiculos. */
  148.  
  149. void salir_vehiculo(){
  150.  
  151.     int plaza = 0;
  152.     char teclo = ' ';
  153.  
  154.     while (teclo != 'P' && teclo != 'G'){
  155.  
  156.         printf("\nIndique la zona (G/P)): ");
  157.  
  158.         scanf("%c", &teclo);
  159.         flush_stdin();
  160.         teclo = toupper (teclo);
  161.  
  162.         if(teclo != 'P' && teclo != 'G'){
  163.             printf("\nCOMANDO INCORRECTO\n");
  164.         }
  165.  
  166.         if (teclo == 'P'){
  167.  
  168.             printf("\nIndique la plaza (1-15)): ");
  169.  
  170.             scanf("%d", &plaza);
  171.             flush_stdin();
  172.  
  173.             if (Vector_ParkingP[plaza]){
  174.                 Vector_ParkingP[plaza] = false;
  175.                 printf("\n\nEl vehiculo ha abandonado la plaza:\n\n");
  176.  
  177.             } else {
  178.                 printf("\n\nERROR: No hay vehiculo en esa plaza:\n\n");
  179.             }
  180.         }
  181.  
  182.         if (teclo == 'G'){
  183.  
  184.             printf("\nIndique la plaza (1-10)): ");
  185.  
  186.             scanf("%d", &plaza);
  187.             flush_stdin();
  188.  
  189.             if (Vector_ParkingG[plaza]){
  190.                 Vector_ParkingG[plaza] = false;
  191.                 printf("\n\nEl vehiculo ha abandonado la plaza:\n\n");
  192.  
  193.  
  194.             } else {
  195.                 printf("\n\nERROR: No hay vehiculo en esa plaza:\n\n");
  196.             }
  197.         }
  198.     }
  199.     teclo = ' ';
  200.     imprimir_parking();
  201. }
  202.  
  203. /* Programa principal. */
  204.  
  205. int main (){
  206.  
  207.     char accion = ' ';
  208.  
  209.     do{
  210.  
  211.         printf("\nIndique acción a realizar (Si entra vehiculo pulse 'E', si sale vehiculo pulse 'S', si desea observar el estado del parking pulse 'O', si desea finalizar el programa pulse 'F'): ");
  212.         scanf("%c", &accion);
  213.         flush_stdin();
  214.         accion = toupper (accion);
  215.  
  216.         switch (accion) {
  217.  
  218.             case 'E':
  219.             entrar_vehiculo();
  220.             break;
  221.  
  222.             case 'S':
  223.             salir_vehiculo();
  224.             break;
  225.  
  226.             case 'O':
  227.             printf("\n\n");
  228.             imprimir_parking();
  229.             break;
  230.  
  231.             default:
  232.             printf("\nCOMANDO INCORRECTO\n");
  233.         }
  234.  
  235.     } while (accion != 'F');
  236.  
  237.     return 0;
  238. }

Gracias a todos por vuestra ayuda ;)

Etiquetas: funcion, int, programa, scanf
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 13:01.