9

Tengo un problema con un ciclo de while. Quiero que mi programa únicamente acepte números de 4 cifras, y, si el usuario ingresa uno fuera del rango, que salte error.

Había hecho esto, pero noté que a partir de cierto número de cifras, el programa terminando arrojando solo la línea de error. Me gustaría saber qué estoy haciendo mal.

#include iostream

int main()
{
    int a=1, b;
    std::cin >> b;
    while (b > 9999 || b < 1110) {
        std::cout << "\nE R R O R. Favor de ingresar un numero de cuatro digitos.\n";
        std::cin >> b;
    }
    std::cout << b;

    system("pause");
}
eferion
  • 49,291
  • 5
  • 30
  • 72
Caro GS
  • 123
  • 7
  • 1
    `#include iostream` no funciona, intenta `#include `. Además [a tu `main` le falta el retorno](https://es.stackoverflow.com/questions/139624/en-c-es-obligatorio-incluir-el-return-0-dentro-de-la-funci%C3%B3n-main). – PaperBirdMaster Feb 26 '18 at 08:11

2 Answers2

6

pero noté que a partir de cierto número de cifras, el programa terminando arrojando solo la línea de error.

Los números los estás almacenando en b, que es de tipo int. El tipo int es un tipo de dato entero con signo. Este tipo de dato, de 32 bits, usa un bit para almacenar el signo y los 31 restantes para almacenar el número propiamente dicho.

Es decir, para 31 bits, el número más grande que puede admitir es: 2^31-1 = 2.147.483.647.

Si intentas introducir un número más grande, cin no podrá almacenarlo en la variable y esto hace que se active un flag de error... a partir de ese momento cin se bloquea hasta que trates el error.

Lo más habitual en estos casos es limpiar el flag de error y vaciar el buffer de entrada:

while (b > 9999 || b < 1110) {
    std::cout << "\nE R R O R. Favor de ingresar un numero de cuatro digitos.\n";
    std::cin >> b;
    if( std::cin.fail() )
    {
      std::cin.ignore(std::numeric_limits<int>::max(),'\n');
      std::cin.clear();
    }
}

Donde:

  • numeric_limits es una plantilla de C++ que te proporciona información sobre los tipos numéricos. En este caso le estamos pidiendo el valor más alto que puede ser almacenado en una variable de tipo int. numeric_limits se encuentra en la librería limits.
  • cin.ignore descarta caracteres de entrada... en este caso descartará todo lo que haya hasta que se encuentre con un salto de línea (que también será descartado). El primer parámetro indica el número de bytes a descartar... de ahí que se use numeric_limits... queremos descartar el máximo posible.
  • cin.clear resetea el flag de error, lo que hace que cin vuelva a estar disponible para leer nuevos valores.

EDITO

El problema de la respuesta anterior es que no contempla el caso de que se introduzca una entrada incorrecta en la primera iteración. No me gusta repetir código, por lo que una posible solución sería la siguiente:

int main()
{
    int b;
    bool pedirNumero = true;
    while(pedirNumero)
    {
        std::cin >> b;
        pedirNumero = std::cin.fail() || b > 9999 || b < 1110;

        if( pedirNumero )
        {
          std::cout << "\nE R R O R. Favor de ingresar un numero de cuatro digitos.\n";
          std::cin.ignore(std::numeric_limits<int>::max(),'\n');
          std::cin.clear();
        }
    }
    std::cout << b;
}
eferion
  • 49,291
  • 5
  • 30
  • 72
  • Antes que nada, ¡muchas gracias! Llevaba desde ayer atorada en eso. Sabía que los datos de tipo entero tenían un límite, pero no terminaba de comprender qué tan fácil era llegar a este. Pero ahora tengo otro problema. Al momento de que el usuario ingresa un número que excede el límite del entero, salta la linea de error dos veces. ¿Sabe usted por qué ocurre esto? – Caro GS Feb 26 '18 at 07:17
  • @CaroGS De nada, para eso estamos aquí. Por cierto, bienvenida a StackOverflow. Si la respuesta soluciona tu problema no olvides marcarla como solución (si hay varias respuestas que solucionan tu problema elige la que más se aproxime). Así contribuyes al buen funcionamiento de este portal – eferion Feb 26 '18 at 07:19
  • ¡Gracias de nuevo!! Pero, ¿qué podría hacer para que no salte la segunda línea de error? – Caro GS Feb 26 '18 at 07:25
  • @CaroGS He editado la respuesta... si no soluciona tu problema quizás debas editar la pregunta y ser más explícita con eso de que "*no salte la segunda línea de error*" con un ejemplo práctico, la salida que recibes y la que esperas. – eferion Feb 26 '18 at 07:31
3

Yo te propondría un cambio de estrategia. En lugar de capturar números captura cadenas de caracteres (el límite de longitud de las cadenas de caracteres es tan grande como permita la memoria del ordenador). Con las cadenas de caracteres no tendrás límite alguno a la longitud de los números de entrada.

Una vez capturada la cadena puedes comprobar si es de longitud 4 y si está formada por números:

std::string b;
std::cin >> b;
while ((b.length() != 4) || !std::all_of(b.begin(), b.end(), [](char c) { return std::isdigit(c) != 0; })) {
    std::cout << "\nE R R O R. Favor de ingresar un numero de cuatro digitos.\n";
    std::cin >> b;
}

La función std::all_of comprueba que todos los elementos entre los iteradores facilitados cumplan con una condición, en este caso comprobamos que todos sean números con std::isdigit, que devuelve 0 cuando el carácter facilitado no es un dígito.

Puedes ver el código funcionando en Wandbox 三へ( へ՞ਊ ՞)へ ハッハッ.

PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82