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

Validar solo números en un INT

Estas en el tema de Validar solo números en un INT en el foro de C/C++ en Foros del Web. Código: int NumeroLetras; do { cout << "\nN\243mero de letras de la palabra: "; cin >> NumeroLetras; } while(ValidarNumeroIngresado(NumeroLetras)); /* Validar el número ingresado ------------------------------------------------------------------------*/ ...
  #1 (permalink)  
Antiguo 04/11/2015, 17:01
RGT
Usuario no validado
 
Fecha de Ingreso: noviembre-2008
Mensajes: 505
Antigüedad: 15 años, 5 meses
Puntos: 5
Pregunta Validar solo números en un INT

Código:
int NumeroLetras;

do
    {
        cout << "\nN\243mero de letras de la palabra: ";
        cin >> NumeroLetras;
    } while(ValidarNumeroIngresado(NumeroLetras));

/*  Validar el número ingresado
------------------------------------------------------------------------*/
int ValidarNumeroIngresado(int NumeroLetras)
{
    if (NumeroLetras < 48 || NumeroLetras > 57)
        return 0;

    else
        return 1;
}
Hola, me deje llevar por la tabla del codigo ASCHII, si se ingresa algo fuera de ese rango, no es considerado un número, pero no funciona.

Alguien sabe mi error?.
Investigué en Google y encuentro muchas formas diferentes, pero para serles sincero no las entiendo.

Espero puedan ayudarme chicos..
  #2 (permalink)  
Antiguo 04/11/2015, 17:34
Avatar de xKuZz  
Fecha de Ingreso: febrero-2015
Ubicación: nullptr
Mensajes: 183
Antigüedad: 9 años, 2 meses
Puntos: 27
Respuesta: Validar solo números en un INT

Aunque devolver 0 o 1 es correcto, es, al menos en mi opinión más apropiado utilizar el tipo bool que el lenguaje nos ofrece. Dicho tipo bool puede tomar dos valores: true (si es verdadero) o false (si es falso).

Vamos a tu código el error es muy simple.

Código C++:
Ver original
  1. int NumeroLetras;
  2. cin >> NumeroLetras; // Esto implica que el número que introduzca ya sea 5, 20 o 40000 se almacena en NumeroLetras
  3.  
  4. ....
  5.  
  6. bool ValidarNumeroIngresado(int NumeroLetras){
  7.    if (NumeroLetras < 48 || NumeroLetras >57)
  8.       return false;
  9.    else
  10.       return true; // Devuelvo verdadero si el int esta en el rango [49,57]

Tu código devolverá verdadero sin introduzco por pantalla enteros del 49 al 57 ambos inclusive, que obviamente no es lo que quieres.

¿Cómo puedes solucionarlo? Hay mil y una forma de hacerlos pero vamos a centrarnos en la más simple para este pequeño trozo de código.

cin tiene asociados unos bits de estado que se activan bajo ciertas circunstancias. Vamos a ir a una circunstancia que provocaría dicho comportamiento. Si yo ejecutase tu programa y e introduzco alguna cosa que no es un entero el bit de fail se activa. Para comprobar que si dicho bit está activado está el método cin.fail().

Nota: Tanto fail() como otros tres bits de estado son comunes para todo flujo, ya sea cin/cout o un archivo fstream.

Además por la naturaleza de tu ejemplo, podemos estar seguros de que quieres un valor estrictamente mayor que 0 y menor o igual que el tamaño de la mayor palabra. Así pues una posible solución al problema encontrado sería:

Código C++:
Ver original
  1. const int kMAXTAM=10 // Supongo que la palabra más grande que puedo usar tiene 10 letras
  2. int NumeroLetras;
  3. cin >> NumeroLetras;
  4. if(cin.fail() || NumeroLetras<=0 || NumeroLetras>kMAXTAM){
  5.    // Lo que se hace cuando no es correcto
  6. }
  7. else {
  8.   // Lo que se hace cuando es correcto
  9. }
  #3 (permalink)  
Antiguo 04/11/2015, 20:20
RGT
Usuario no validado
 
Fecha de Ingreso: noviembre-2008
Mensajes: 505
Antigüedad: 15 años, 5 meses
Puntos: 5
Respuesta: Validar solo números en un INT

Cita:
Iniciado por xKuZz Ver Mensaje
Aunque devolver 0 o 1 es correcto, es, al menos en mi opinión más apropiado utilizar el tipo bool que el lenguaje nos ofrece. Dicho tipo bool puede tomar dos valores: true (si es verdadero) o false (si es falso).

Vamos a tu código el error es muy simple.

Código C++:
Ver original
  1. int NumeroLetras;
  2. cin >> NumeroLetras; // Esto implica que el número que introduzca ya sea 5, 20 o 40000 se almacena en NumeroLetras
  3.  
  4. ....
  5.  
  6. bool ValidarNumeroIngresado(int NumeroLetras){
  7.    if (NumeroLetras < 48 || NumeroLetras >57)
  8.       return false;
  9.    else
  10.       return true; // Devuelvo verdadero si el int esta en el rango [49,57]

Tu código devolverá verdadero sin introduzco por pantalla enteros del 49 al 57 ambos inclusive, que obviamente no es lo que quieres.

¿Cómo puedes solucionarlo? Hay mil y una forma de hacerlos pero vamos a centrarnos en la más simple para este pequeño trozo de código.

cin tiene asociados unos bits de estado que se activan bajo ciertas circunstancias. Vamos a ir a una circunstancia que provocaría dicho comportamiento. Si yo ejecutase tu programa y e introduzco alguna cosa que no es un entero el bit de fail se activa. Para comprobar que si dicho bit está activado está el método cin.fail().

Nota: Tanto fail() como otros tres bits de estado son comunes para todo flujo, ya sea cin/cout o un archivo fstream.

Además por la naturaleza de tu ejemplo, podemos estar seguros de que quieres un valor estrictamente mayor que 0 y menor o igual que el tamaño de la mayor palabra. Así pues una posible solución al problema encontrado sería:

Código C++:
Ver original
  1. const int kMAXTAM=10 // Supongo que la palabra más grande que puedo usar tiene 10 letras
  2. int NumeroLetras;
  3. cin >> NumeroLetras;
  4. if(cin.fail() || NumeroLetras<=0 || NumeroLetras>kMAXTAM){
  5.    // Lo que se hace cuando no es correcto
  6. }
  7. else {
  8.   // Lo que se hace cuando es correcto
  9. }
Excelente explicacion hermano pero no entendi lo de kMAXTAM=10, fue lo unico.,....
  #4 (permalink)  
Antiguo 05/11/2015, 03:16
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 2 meses
Puntos: 3
Respuesta: Validar solo números en un INT

Tengo una duda al respecto. cin se que tiene fail() y good() para controlar si algo falló. Mi duda es que si introduces un entero mayor que el valor máximo permitido ¿el bit de fail estaría a true? En un depurador como ollydbg si examinas un binario y un entero se desborda se activa el Flag O ¿cin tiene algún bit para controlar eso?
Y si en vez de cin es un simple int que voy incrementando ¿como puedo saber si el int se desbordó?
Por ejemplo:
Código C++:
Ver original
  1. int a=10,b=10;
  2. bool salir=false;
  3. do {
  4.    a *=b;
  5.    b+=a;
  6. while (salir==false);
Ese bucle es infinito pero si quisiera salir si a o b se desborda ¿como lo haría? No vale comparar con el valor máximo porque al desbordarse valdría siempre menos.
  #5 (permalink)  
Antiguo 05/11/2015, 03:19
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 7 meses
Puntos: 204
Respuesta: Validar solo números en un INT

Cita:
Iniciado por RGT Ver Mensaje
Excelente explicacion hermano pero no entendi lo de kMAXTAM=10, fue lo unico.,....
Sirve para indicar el número máximo que vas a admitir como válido.

¿Por qué usar una constante en vez de poner el valor "a pelo"? Porque es una buena práctica de programación.

Normalmente un valor constante se suele reutilizar varias veces en el código (por ejemplo el tamaño máximo de una matriz, o un número mágico usado para delimitar, ...

Si los valores constantes los encierras en una variable constante consigues de un plumazo varias cosas:
  • El valor puede ser utilizado con facilidad en varias partes del código
  • Si en el futuro ese valor cambia, únicamente tendrás que modificarlo en un sitio... esto evita muchos errores.
  • Tener el valor en una constante te permite identificar qué valores están relacionados entre sí y cuales no. Esto quiere decir que no es muy útil tener, por ejemplo: const int diez = 10; y reutilizar este valor por doquier... el nombre de la constante tiene que ser representativo y no hay que reutilizar la misma constante para cosas diferentes.
Un saludo
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #6 (permalink)  
Antiguo 05/11/2015, 09:49
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 2 meses
Puntos: 3
Respuesta: Validar solo números en un INT

Despues de quebrarme el coco un poco he conseguido dos formas de hacer lo que pedia:

Código C++:
Ver original
  1. //---------------------------------------------------------------------------
  2. #include <iostream>
  3. #include <cstring.h>
  4.  
  5. bool ObtenerEnteroMetodo1(int *valor);
  6. int ObtenerEnteroMetodo2(int *valor);
  7.  
  8. int main(int argc, char* argv[])
  9. {
  10.    int valor;
  11.  
  12.    switch(ObtenerEnteroMetodo2(&valor)){
  13.       case 0:
  14.          std::cout << "El valor resultante es: " << valor;
  15.          break;
  16.       case 1:
  17.          std::cout << "Huvo Overflow" << std::endl;
  18.          break;
  19.       case 2:
  20.          std::cout << "Formato invalido para un entero" << std::endl;
  21.          break;
  22.    }
  23.  
  24.    return 0;
  25. }
  26. //---------------------------------------------------------------------------
  27.  
  28. bool ObtenerEnteroMetodo1(int *valor)
  29. {
  30.    bool error=false;
  31.    std::cout<<"Introduce un valor entero: ";
  32.    std::cin >> *valor;
  33.  
  34.    //Metodo 1 para comprobar overflow de entero al obtenerlo con cin
  35.    //Este metodo no discrimina entre el fallo, o sea, si meto una cadena
  36.    //que no puede convertir en un numero dará fallo pero no podré saber
  37.    //que fallo dio
  38.    if(std::cin.fail()){
  39.       error=true;
  40.    }
  41.    return !error;
  42. }
  43. //---------------------------------------------------------------------------
  44.  
  45. int ObtenerEnteroMetodo2(int *valor)
  46. {
  47.    //Metodo 2 para comprobar overflow de entero al obtenerlo con cin
  48.    //Creo que es el mas completo
  49.    string cadena;
  50.    int valorbackup;
  51.    int error=0,negativo=false;
  52.  
  53.    *valor=0;
  54.    std::cout<<"Introduce un valor entero: ";
  55.    std::cin >> cadena;
  56.    for(int i=0; i < cadena.length();i++){
  57.       if(cadena[i] >='0' && cadena[i] <='9'){
  58.          valorbackup=*valor;
  59.          *valor*=10;
  60.          *valor += (cadena[i]-'0');
  61.          if(valorbackup != *valor/10){
  62.             error=1; //Huvo overflow
  63.             break;
  64.          }
  65.       }else if(i==0 && cadena[i] =='-'){
  66.          negativo=true;
  67.       }else{
  68.          error=2; //Cadena con formato invalido
  69.          break;
  70.       }
  71.    }
  72.    if(negativo)
  73.       *valor *= -1; //Convertir el numero en negativo
  74.    return error;
  75. }

Me gusta como ha quedado el metodo 2 pero si veis como mejorarlo soy todo oidos jejeje.

Última edición por aguml; 05/11/2015 a las 10:14
  #7 (permalink)  
Antiguo 05/11/2015, 10:34
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 7 meses
Puntos: 204
Respuesta: Validar solo números en un INT

Venga, yo también quiero :)

Código C++:
Ver original
  1. enum class ConvertError
  2. {
  3.   NoError,
  4.   Overflow,
  5.   WrongFormat
  6. };
  7.  
  8. ConvertError ToInt( std::istream& stream, int& value )
  9. {
  10.   ConvertError toReturn = ConvertError::NoError;
  11.  
  12.   bool negate = false;
  13.   bool firstChar = true;
  14.   value = 0;
  15.   bool nextIteration = true;
  16.   do
  17.   {
  18.     char c = stream.peek();
  19.  
  20.     if( c == EOF )
  21.       nextIteration = false;
  22.     else
  23.     {
  24.       stream.get(); // discard from the stream
  25.  
  26.       if( c==' ' || c=='\n' || c=='\r' || c=='\t' )
  27.         nextIteration = false;
  28.       else if( isdigit(c) )
  29.       {
  30.         int newValue = value*10+c-'0';
  31.         if( newValue < value )
  32.         {
  33.           nextIteration = false;
  34.           toReturn = ConvertError::Overflow;
  35.         }
  36.         value = newValue;
  37.       }
  38.       else
  39.       {
  40.         if( (c != '-' && c != '+') || !firstChar )
  41.         {
  42.           nextIteration = false;
  43.           toReturn = ConvertError::WrongFormat;
  44.         }
  45.         else
  46.           negate = (c=='-');
  47.       }
  48.     }
  49.     firstChar = false;
  50.   } while(nextIteration);
  51.  
  52.   if( negate )
  53.     value *= -1;
  54.  
  55.   return toReturn;
  56. }
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #8 (permalink)  
Antiguo 05/11/2015, 10:45
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 2 meses
Puntos: 3
Respuesta: Validar solo números en un INT

guauuu. ¿y eso como se usa? ¿puedes poner un ejemplo donde pueda compilarlo para ver como funciona y depurarlo a ver si me entero?
Creo que entiendo lo que hace tu funcion pero lo que haces de enum class no soy capaz de que compile.
Edito:
Tuve que modificar tu codigo porque eso que pones de enum class mi compilador no se lo traga y supongo que o bien el compilador que uso es anterior a c++11 que creo que es donde se metio eso segun he leido, o bien no es estandard o yo que se jajaja.
Asi lo he dejado:
Código C++:
Ver original
  1. //---------------------------------------------------------------------------
  2. #include <iostream>
  3. #include <sstream>
  4.  
  5. using namespace std;
  6.  
  7. enum ConvertError
  8. {
  9.   NoError,
  10.   Overflow,
  11.   WrongFormat
  12. };
  13. //---------------------------------------------------------------------------
  14.  
  15. ConvertError ToInt( std::istream& stream, int& value )
  16. {
  17.   ConvertError toReturn = NoError;
  18.  
  19.   bool negate = false;
  20.   bool firstChar = true;
  21.   value = 0;
  22.   bool nextIteration = true;
  23.   do
  24.   {
  25.     char c = stream.peek();
  26.  
  27.     if( c == EOF )
  28.       nextIteration = false;
  29.     else
  30.     {
  31.       stream.get(); // discard from the stream
  32.  
  33.       if( c==' ' || c=='\n' || c=='\r' || c=='\t' )
  34.         nextIteration = false;
  35.       else if( isdigit(c) )
  36.       {
  37.         int newValue = value*10+c-'0';
  38.         if( newValue < value )
  39.         {
  40.           nextIteration = false;
  41.           toReturn = Overflow;
  42.         }
  43.         value = newValue;
  44.       }
  45.       else
  46.       {
  47.         if( (c != '-' && c != '+') || !firstChar )
  48.         {
  49.           nextIteration = false;
  50.           toReturn = WrongFormat;
  51.         }
  52.         else
  53.           negate = (c=='-');
  54.       }
  55.     }
  56.     firstChar = false;
  57.   } while(nextIteration);
  58.  
  59.   if( negate )
  60.     value *= -1;
  61.  
  62.   return toReturn;
  63. }
  64. //---------------------------------------------------------------------------
  65.  
  66. int main(int argc, char* argv[])
  67. {
  68.    stringstream stream;
  69.    string aux;
  70.    int valor;
  71.    cin >> aux;
  72.    stream <<aux;
  73.    switch(ToInt(stream,valor)){
  74.       case 0:
  75.          cout<<"El valor es: "<<valor<<endl;
  76.          break;
  77.       case 1:
  78.          cout<<"Huvo overflow"<<endl;
  79.          break;
  80.       case 2:
  81.          cout<<"Formato incorrecto"<<endl;
  82.          break;
  83.    }
  84.    return 0;
  85. }
  86. //---------------------------------------------------------------------------

Por cierto no sabia que un enum se podia usar como tipo de retorno.
Otra cosa ¿que virtudes tiene tu codigo con respecto al mio?
Y si quieres echar un vistazo a como hago para ejecutar tu funcion y me dices si es correcto o hay un camino mas corto para no tener que usar stringstream...

Última edición por aguml; 05/11/2015 a las 11:18
  #9 (permalink)  
Antiguo 05/11/2015, 14:32
Avatar de xKuZz  
Fecha de Ingreso: febrero-2015
Ubicación: nullptr
Mensajes: 183
Antigüedad: 9 años, 2 meses
Puntos: 27
Respuesta: Validar solo números en un INT

No tienes porqué utilizar stringstream para nada. Al final te dejo un ejemplo.

La principal ventaja que tiene el código de eferion es que extremadamente legible, cualquier persona con un poco de idea de inglés y el lenguaje es capaz de comprender al instante lo que su código hace.

Cómo usarlo:

Código C++:
Ver original
  1. int main()
  2. {
  3.    int valor;
  4.    switch(ToInt(cin ,valor)){
  5.       case NoError:
  6.          cout<<"El valor es: "<<valor<<endl;
  7.          break;
  8.       case Overflow:
  9.          cout<<"Hubo overflow"<<endl;
  10.          break;
  11.       case WrongFormat:
  12.          cout<<"Formato incorrecto"<<endl;
  13.          break;
  14.    }
  15.  
  16. }
  #10 (permalink)  
Antiguo 05/11/2015, 16:15
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 2 meses
Puntos: 3
Respuesta: Validar solo números en un INT

¿Seguro que eso funciona así? Lo digo porque usas cin como parámetro pero no veo que uses ni operador de sobrecarga, ni getline, ni nada. ¿que se supone que va a leer en la función ?
  #11 (permalink)  
Antiguo 06/11/2015, 01:22
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 7 meses
Puntos: 204
Respuesta: Validar solo números en un INT

Cita:
Iniciado por aguml Ver Mensaje
¿Seguro que eso funciona así? Lo digo porque usas cin como parámetro pero no veo que uses ni operador de sobrecarga, ni getline, ni nada. ¿que se supone que va a leer en la función ?
La función recibe como parámetro un istream, que es el padre de todos los mecanismos de entrada ofrecidos por la STL. Esto quiere decir que puedes usarlo tanto para leer un dato de un fichero como del teclado.

Funciona porque en C++ existe el polimorfismo, que es lo que permite gestionar cualquier entrada sin importar su tipo concreto.

Por cierto, como comentabas en el mensaje anterior, efectivamente el código que hice esta hecho en C++11. Pero si quitas el "class" del enum debería compilar perfectamente en versiones anteriores de C++.

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #12 (permalink)  
Antiguo 06/11/2015, 05:45
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 2 meses
Puntos: 3
Respuesta: Validar solo números en un INT

Ok, entonces con lo que pone xKuZz se quedaría esperando la entrada del teclado siempre y cuando no haya datos ya en el ¿no? Igual que hace cin con getline, o get, o el operador de sobrecarga ¿no?
Muy interesante.
Por cierto estoy liado ahora con el polimorfismo y la herencia y ganas de llorar tengo jajaja. Es complejo tela.
  #13 (permalink)  
Antiguo 06/11/2015, 07:06
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 7 meses
Puntos: 204
Respuesta: Validar solo números en un INT

Cita:
Iniciado por aguml Ver Mensaje
Ok, entonces con lo que pone xKuZz se quedaría esperando la entrada del teclado siempre y cuando no haya datos ya en el ¿no?
Exacto.

Cita:
Iniciado por aguml Ver Mensaje
Igual que hace cin con getline, o get, o el operador de sobrecarga ¿no?
correcto.

Cita:
Iniciado por aguml Ver Mensaje
Por cierto estoy liado ahora con el polimorfismo y la herencia y ganas de llorar tengo jajaja. Es complejo tela.
El polimorfismo no es más que una característica de abstracción... su uso es, mayormente, poder utilizar una lista compuesta de objetos de diferentes clases usando para ello una clase padre común.

La herencia tampoco es demasiado complicada si no te dedicas a putearte... intenta diseñar las cosas siempre con herencia simple y procura que, de necesitar herencia compuesta, ésta se componga de interfaces (clases virtuales puras) y, como mucho, de una clase no virtual.

Lo más complicado de la herencia es saber aplicarla correctamente. No es lo mismo "A es B" (herencia) que "A contiene B" (no herencia) o "A usa B" (no herencia). Además la programación añade esa capa de intangencia que a la gente le cuesta muchísimo asimilar, dicho en cristiano. Un objeto no tiene que representar un elemento de la vida real sino más bien un concepto. El tener una clase "Coche" con 4 objetos de clase "Rueda" no tiene por qué ser necesariamente el mejor diseño. No se si me explico. Pues con la herencia pasa exactamente lo mismo... muchas veces la gente confunde una composición con una herencia y un exceso de herencia es algo bastante malo, ya que te obliga a arrastrar mucha información que no necesitas para nada... pero como la estás arrastrando también tienes que estar pendiente de ella.

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.

Etiquetas: funcion, int, numero
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 06:22.