Целочисленное переполнение

Целочисленное переполнение

Всем привет!
Учусь программировать на C++, после прохождения всех уроков с этого сайта, решил прочитать книгу Гилберта Шилдта. В одной из программ, при вводе значения переменной short int guess с клавиатуры размером больше данного типа данных, т.е. например 50000, цикл for (attempts = 0; attempts < 100; attempts++) в функции void play(int m) начинает повторяться уже не требуя ввод клавиатуры, как бы зависает в цикле. Не помогло и переопределение переменной внутри вначале цикла, а так же проверки на переполнение, подскажите как можно решить данную проблему. Программа не серьезная, но на будущее хотелось бы быть готовым к таким проблемам. Пользуюсь Visual Studio 2015. При вводе значений нормальной размерности, все работает как часы. Решения типа поменять тип переменной на double не предлагать, т.к. по сути можно ввести число размера 10000000000000000000000000000000, и программу так же заглючит.

Скрин глюка:
Скриншот ошибки Visual Studio 2015

#include <iostream>
#include <cstdlib>

void play(int m);
int main()
{
    int option;
    int magic;
    magic = rand();
    do {
        std::cout << "1. Get the new magic number\n";
        std::cout << "2. Play\n";
        std::cout << "3. Exit\n";
        do {
            std::cout << "Enter menu item: ";
            std::cin >> option;
        } while (option < 1 || option > 3);
        switch (option) {
        case 1:
            magic = rand();
            std::cout << "--> Ok\n";
            break;
        case 2:
            play(magic);
            break;
        case 3:
            std::cout << "Good bye!\n";
            break;
        }
    } while (option != 3);

    system("pause");
    return 0;
}

void play(int m)
{
    short int attempts, guess;
    for (attempts = 0; attempts < 100; attempts++) {
        std::cout << "Guess the magic number: ";
        std::cin >> guess;
        // Проверка на переполнение --- не помогла:(
        if (guess > std::numeric_limits<short int>::max()) {
            std::cout << "A number is very big. Please try again.\n";
            throw std::overflow_error("Integer overflow");
        }
        if (guess == m) {
            std::cout << "*** True ***\n";
            return;
        }
        else {
            if (guess < m) std::cout << "More.\n";
            else std::cout << "Less.\n";
        }
    }
    std::cout << "Exceeded the number of attempts to guess the number."
        << "Try again.\n";
}

// Проверка на переполнение —- не помогла:(

А как Вы узнаете, что число больше максимума? Максимум для данного типа на то и максимум, что число не может быть больше :)

Хреновое решение:

#include <iostream>
#include <cstdlib>

void play(short int m);
int main()
{
    int option;
    int magic;
    magic = rand();
    do {
        std::cout << "1. Get the new magic number\n";
        std::cout << "2. Play\n";
        std::cout << "3. Exit\n";
        do {
            std::cout << "Enter menu item: ";
            std::cin >> option;
        } while (option < 1 || option > 3);
        switch (option) {
        case 1:
            magic = rand();
            std::cout << "--> Ok\n";
            break;
        case 2:
            play(magic);
            break;
        case 3:
            std::cout << "Good bye!\n";
            break;
        }
    } while (option != 3);

    return 0;
}

void play(short int m)
{
    short int attempts, guess;
    for (attempts = 0; attempts < 100; attempts++) {
        std::cout << "Guess the magic number: ";
        while ( !(std::cin >> guess) )
        {
            (std::cout << "Input error. Please, try again\nGuess the magic number: ").flush() ;
            std::cin.clear() ;
            std::cin.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' ) ;
        }
        if (guess == m) {
            std::cout << "*** True ***\n";
            return;
        }
        else {
            if (guess < m) std::cout << "More.\n";
            else std::cout << "Less.\n";
        }
    }
    std::cout << "Exceeded the number of attempts to guess the number."
        << "Try again.\n";
}

А как Вы узнаете, что число больше максимума? Максимум для данного
типа на то и максимум, что число не может быть больше :)

Хреновое решение:

Спасибо. Понял свою ошибку по поводу проверки:)

А почему хреновое решение?

А для чего в строке (std::cout << "Input error. Please, try again\nGuess the magic number: ").flush() ; в конце flush() и без него вроде работает нормально?
std::cin.clear() ; — это как я понял основной момент, который отчистит поток ввода и уберет рекурсию, верно?
std::cin.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' ) ; — можете объяснить что делает эта строка? В общих чертах понял, что что-то обрезает, и как показал опыт, решает проблему ввода символов вместо цифр.

Так лучше?

void play(int m)
{
    short int attempts, guess;
    for (attempts = 0; attempts < 100; attempts++) {
        std::cout << "Guess the magic number: ";
        std::cin >> guess;

        // Проверка на переполнение ---------
        if (std::cin.fail()) {
            std::cout << "Overflow!" << std::endl;
            std::cin.clear();
            std::cin.ignore();
            // break;                                       // вариант 1
            throw std::overflow_error("Integer overflow");  // вариант 2
        }
        // -----------------------------------

        if (guess == m) {
            std::cout << "*** True ***\n";
            return;
        }
        else {
            if (guess < m) std::cout << "More.\n";
            else std::cout << "Less.\n";
        }
    }
    std::cout << "Exceeded the number of attempts to guess the number."
        << "Try again.\n";
}

Целесообразнее, конечно, сделать в виде функции. Поскольку в этой программе засада с переполнением имеется не только с short guess, но и с int option в main().

Также fail() (точнее говоря, поток) будет реагировать и на попытку нецифрового ввода, когда ожидается число. Так что "Overflow" тут весьма относительное ))

strel, RTFM! Хотя бы тот, который идёт в поставке Visual Studio. Или здесь.

std::cin.clear(); — это как я понял основной момент, который отчистит поток ввода и уберет рекурсию, верно?

Не верно. Совсем не верно. RTFM — без этого — никак (

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.

Ответить

Вы можете использовать разметку markdown для оформления комментариев и постов. Используйте функцию предпросмотра для проверки корректности разметки.

Пожалуйста, оформляйте исходный код в соответствии с правилами разметки. Для того, чтобы вставить код в комментарий, скопируйте его в текстовое поле ниже, после чего выделите то, что скопировали и нажмите кнопку «код» в панели инструментов. Иначе ваш код может принять нечитаемый вид.

Либо производите оформление кода вручную, следующим образом:

``` #include <iostream> using namespace std; int main() { // ... } ```

Предпросмотр сообщения

Ваше сообщение пусто.