C++ вопрос по CIN

144
10 декабря 2019, 21:50

Есть маленькая прогаммка, все ничего, но столкнулся с одной странной трудностью. Приложен код простой менюшки, которая обёрнута в цикл do while и через switch отсылает пользователя в другие подменю. Принимает в работу введенные значения от 0 до 7. При вводе "0" программа закрывается. Вот в чем проблема: cin.clear() и cin.ignore() сбрасывают флаги и чистят буфер после каждого ввода, что избавляет от трудностей с некорректным вводом (select имеет тип int), заставляя повторять его, до тех пор пока не будет введено что-то вразумительное, чего программа ожидает. Но есть одно маленькое "но". При вводе чисел в cin никаких ошибок не пишется, просто перезапускается цикл, если число не подходит. Но если ввести какой-либо символ, в потоке выпадет ошибка, а после отработки cin.clear() cin.ignore() переменная select магическим(?) образом станет равна "0" и программа закроется. Можно конечно переставить эту функцию на 9, к примеру, но хочется понять тему и сделать более-менее без костылей.

do {                    // Starting <do while> cycle for selection. Wro

        cout << "Input: ";
        cin >> select;                                      // This var lives only in private sector in current class
        cin.clear();                                        //сбрасываем ошибку
        cin.ignore(numeric_limits<streamsize>::max(), '\n'); //удаляем все из буфера до перевода строки

        switch (select) {
        case 0:
            exit (0);
        case 1:
            menuVariables();
            break;
        case 2:
            menuCycles();
            break;
        case 3:
            menuArrays();
            break;
        case 4:
            menuFunctions();
            break;
        case 5:
            menuOperators();
            break;
        case 6:
            menuPointers();
            break;
        case 7:
            menuLibraries();
            break;
        case 666:
            cout << "\nBingo, you're little satan's follower. But try something in 1-7 range, please.\n\n";
            break;
        default:
            cout << "\nWrong input. Try again!\n" << endl;
        }
    }
        while (select < 1 || select > 7);
}

Не могу найти внятной документации по cin и его методам. Вернее, ту что есть - не могу осилить. То ли я тупой, то ли языком таким написано, не для новичка. Буду признателен, если подскажете решение и хоть вкратце разжуёте для танкистов. Спасибо!

Answer 1

Просто измените логику внутри цикла, добавив if-предложение.

do {                    // Starting <do while> cycle for selection. Wro

        cout << "Input: ";
        if ( not ( cin >> select ) )
        {
            cin.clear();                                        //сбрасываем ошибку
            cin.ignore(numeric_limits<streamsize>::max(), '\n'); //удаляем все из буфера до перевода строки
        }
        else
        {
            switch (select) {
            case 0:
                exit (0);
            case 1:
                menuVariables();
                break;
            case 2:
                menuCycles();
                break;
            case 3:
                menuArrays();
                break;
            case 4:
                menuFunctions();
                break;
            case 5:
                menuOperators();
                break;
            case 6:
                menuPointers();
                break;
            case 7:
                menuLibraries();
                break;
            case 666:
                cout << "\nBingo, you're little satan's follower. But try something in 1-7 range, please.\n\n";
                break;
            default:
                cout << "\nWrong input. Try again!\n" << endl;
                break;
            }
        }
    } while ( true );
}
Answer 2

Я бы вообще делал так:

typedef void (*menuFunc)();
void exitFunc() { exit(0); }
// Создаем массив функций; каждый `func[i]` представляет собой 
// вызываемую для значения i функцию. Например, для 1 - это
// menuVariables. exitFunc() сделана специально, чтобы для
// 0 вызывать exit(0).
menuFunc func[] = 
{
    exitFunc,        menuVariables,   menuCycles,     menuArrays,
    menuFunctions,   menuOperators,   menuPointers,   menuLibraries
};
...
for(unsigned int select;; сout << "OK, what is your choise now? ")
{
    // Пока не прочитано значение select или прочитанное значение
    // больше 7 - сбрасываем cin и просим новый ввод.
    while(!((cin>>select) && (select <= 7)))
    {
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
        cout << "Wrong input. Try again: ";
    }
    // Если все введено верно - т.е. именно число, и это
    // число от 1 до 7 - просто вызываем соответствующую функцию.
    func[select]();
}

Не компилировал, но вроде идея понятна?

READ ALSO
Подключение к БД Qt

Подключение к БД Qt

Всем приветМожно ли как-то получить список доступных для подключения БД, а не явно задавать имя БД в методе setDatabaseName() ? Грубо говоря, чтобы...

133
Большая нагрузка на ЦПУ

Большая нагрузка на ЦПУ

При запуске самого простого приложения на OpenGL - очень сильно нагружается ЦП и ГПУ, как это можно исправить?

154
Числа Фибоначчи. Не проходит 6 тест на acmp

Числа Фибоначчи. Не проходит 6 тест на acmp

Последовательностью Фибоначчи называется последовательность чисел F0 = 0, F1 = 1, … , Fk = Fk-1 + Fk-2 (k > 1)Требуется найти наибольший общий делитель...

128
Регистрация DLL библиотеки

Регистрация DLL библиотеки

При попытке регистрации библиотеки выдаёт

120