Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: DarkSorcerer en 25 Noviembre 2013, 11:19 am



Título: Necesito ayuda, validación de números enteros
Publicado por: DarkSorcerer en 25 Noviembre 2013, 11:19 am
Este es un problema que ocurre al ingresar por error un caracter no numerico.

Tengo un programa en que desde el main se despliega un menu (dentro de un ciclo infinito), para que el usuario pueda elegir la opcion que necesito, yo decidi usar un switch para ir a los submenus, la cosa es que el switch solo acepta numeros enteros, ademas, dentro del while hay un bloque try/catch, por que decidi implementar una forma de lanzar una excepcion cuando detecte el problema y para que el programa no se detenga. La excepcion se envia a una funcion "indentificarExcepcion", que no es nada mas que imprimir por pantalla el tipo de error , por ejemplo, cuando se ingrese mal en el menu, mandara un 1 y al procesar la excepcion, saldra por pantalla "Error: Ingrese caracteres no numericos".
El problema que mas me complica es que si ingreso una letra, pareciera ser que el ciclo while se vuelve loco e imprime el menu infinitas veces, por ahi lei que es necesario usar el clear para restablecer "cin" y tambien usar el flag cin.fail(), pero no tengo los resultados esperados. Les dejo mi codigo.


Código
  1.  
  2. #include <cstdlib>
  3. #include <iostream>
  4. #include <windows.h>
  5. #include "Operaciones.h"
  6.  
  7. using namespace std;
  8. using namespace operaciones;
  9.  
  10. void opcion1(){
  11.  
  12.    cout <<"\e[2J";
  13.    cout <<"\n::::: MATRIZ TRASPUESTA :::::\n";  
  14.    continuar();
  15.  
  16. }
  17.  
  18. void opcion2(){
  19.  
  20.    cout <<"\e[2J";
  21.    cout <<"\n::::: ELIMINAR VALOR :::::\n";    
  22.    continuar();
  23.  
  24. }
  25.  
  26. void opcion3(){
  27.  
  28.    cout <<"\e[2J";
  29.    cout <<"\n::::: ELIMINAR COLUMNA :::::\n";
  30.    continuar();
  31.  
  32. }
  33.  
  34. void opcion4(){
  35.  
  36.    cout <<"\e[2J";
  37.    cout <<"\n::::: ELIMINAR MATRIZ :::::\n";  
  38.    continuar();
  39.  
  40. }
  41.  
  42. void opcion5(){
  43.  
  44.    cout <<"\e[2J";
  45.    cout <<"\n::::: SUMA ESPECIAL DE UNA MATRIZ :::::\n";
  46.    continuar();
  47.  
  48. }
  49.  
  50. void opcion6(){
  51.  
  52.    cout <<"\e[2J";
  53.    cout <<"\n::::: AGREGAR VALOR :::::\n";  
  54.    continuar();
  55.  
  56. }
  57.  
  58. void opcion7(){
  59.  
  60.    cout <<"\e[2J";
  61.    cout <<"\n::::: INGRESAR NUEVA MATRIZ :::::\n";
  62.    continuar();
  63.  
  64. }
  65.  
  66. void opcion8(){
  67.  
  68.    cout <<"\e[2J";
  69.    cout <<"\n::::: TODAS LAS MATRICES DEL SISTEMA :::::\n";
  70.    continuar();
  71.  
  72. }
  73.  
  74. int main(int argc, char** argv) {
  75.  
  76.    int opcion;
  77.  
  78.    while(true){
  79.  
  80.        desplegarMenu();
  81.  
  82.        try{
  83.  
  84.            cin >> opcion;
  85.  
  86.            if(cin.fail()){
  87.  
  88.                cin.clear();
  89.                throw 1;
  90.  
  91.            }
  92.  
  93.            switch(opcion){
  94.  
  95.                case 1:
  96.  
  97.                    opcion1();
  98.  
  99.                    break;
  100.  
  101.                case 2:
  102.  
  103.                    opcion2();
  104.  
  105.                    break;
  106.  
  107.                case 3:
  108.  
  109.                    opcion3();
  110.  
  111.                    break;
  112.  
  113.                case 4:
  114.  
  115.                    opcion4();
  116.  
  117.                    break;
  118.  
  119.                case 5:
  120.  
  121.                    opcion5();
  122.  
  123.                    break;
  124.  
  125.                case 6:
  126.  
  127.                    opcion6();
  128.  
  129.                    break;
  130.  
  131.                case 7:
  132.  
  133.                    opcion7();
  134.  
  135.                    break;
  136.  
  137.                case 8:
  138.  
  139.                    opcion8();
  140.  
  141.                    break;
  142.  
  143.                case 9:
  144.  
  145.                    salir();
  146.  
  147.                    break;
  148.            }
  149.  
  150.        }catch(int e){
  151.  
  152.            identificarExcepcion(e);
  153.  
  154.        }
  155.  
  156.  
  157.    }
  158.  
  159.    return 0;
  160. }
  161.  
  162.  


Título: Re: Necesito ayuda, validación de números enteros
Publicado por: xaps en 25 Noviembre 2013, 14:08 pm
Primero de todo, no has puesto un default en el switch y es muy recomendable hacerlo en este caso, ya que con eso te aseguras que cualquier otro valor de la variable opcion que no haya sido explicitado se evalúe.

Aquí tienes más información: http://c.conclase.net/curso/?cap=005c

Ahora bien, si con añadir default no solucionas tu problema, podrías cambiar el tipo de la variable opcion a char, y validar en cada iteración del bucle que el valor del char corresponda a los números del 1 al 9.

Tabla de valores ASCII: http://imagenes.mailxmail.com/cursos/imagenes/3/6/codigo-de-caracteres-ascii_5163_19_1.jpg

Saludos


Título: Re: Necesito ayuda, validación de números enteros
Publicado por: rir3760 en 25 Noviembre 2013, 17:29 pm
El problema que mas me complica es que si ingreso una letra, pareciera ser que el ciclo while se vuelve loco e imprime el menu infinitas veces, por ahi lei que es necesario usar el clear para restablecer "cin" y tambien usar el flag cin.fail(), pero no tengo los resultados esperados.
El problema se debe a que el operador ">>" solo consumirá los caracteres validos para la conversión indicada, si el carácter en turno no es valido se queda en el bufer de la entrada estándar para ser procesado eventualmente.

Para solucionarlo solo debes eliminar el resto de la linea mediante sync o ignore. Un ejemplo sencillo del uso de este ultimo:
Código
  1. #include <iostream>
  2. using std::cout;
  3. using std::cin;
  4. using std::endl;
  5.  
  6. #include <limits>
  7. using std::numeric_limits;
  8.  
  9. int main()
  10. {
  11.   int numero;
  12.  
  13.   while (true) {
  14.      cout << "Introduce un numero: ";
  15.      if (cin >> numero)
  16.         break;
  17.      else {
  18.         cin.clear();
  19.         cin.ignore(numeric_limits<int>::max(), '\n');
  20.      }
  21.   }
  22.  
  23.   cout << "El numero es " << numero << endl;
  24.  
  25.   return 0;
  26. }

Un saludo


Título: Re: Necesito ayuda, validación de números enteros
Publicado por: do-while en 25 Noviembre 2013, 20:37 pm
¡Buenas!

Cuando intentas leer un entero pero introduces un caracter, se activa el failbit de istream. Por lo tanto primero tendrás que intentar leer el dato. Luego comprobar si se ha activado el failbit y si asi ha sucedido, resetearlo y vaciar el buffer de entrada:

Código
  1. while((cin>>dato).fail()) //comprobamos los flags de error con la referencia que devuelve el operador >>
  2. {
  3.    cin.clear(); //reseteamos los flags
  4.    while(cin.get() != '\n'); //leemos todo lo que quede en la entrada
  5.    //Si quieres pones un mensaje de error y vuelves a solicitar los datos
  6. }
  7.  
  8. //Al salir del bucle sabemos que hemos leido el dato que corresponde
  9.  

¡Saludos!