Ввод с проверкой корректности

Здравствуйте.
Пытаюсь реализовать ввод числа, но не просто ввод, а ввод с проверкой корректности.

Пишу так:


#include <iostream>

using namespace std;

int main()
{
    int i;
    bool fail = true;
    do
    {
        cout << "Enter [i]: ";
        cin >> i;
                //Если есть ошибка, выводим сообщение 
        if ( cin.fail() )
            cout << "Fatal input error!" << endl;
        else
            fail = false;

                //Восстановили поток
        cin.clear();    
                //Почистили поток
        cin.ignore( cin.rdbuf()->in_avail() );
    }while( fail );

    cout << "You enter: " << i << endl;
    return 0;
}

Но у этого кода есть проблемы:

  • Если ввести сначала число, а потом без пробелов символы( например 12345asd ), сообщение об ошибке не выведется, а в i будет записано 12345( для примера выше ).
  • Если ввести сначала символы, то сообщение об ошибке будет выводится вечно, хотя есть восстановление потока и его очистка.

Под конец стандартный вопрос: В чём дело?

UPD
Если пользоваться кодом из вот этой статьи, то по второму пункту будет всё чуть лучше. Сообщение об ошибке не будет выводиться вечно, а выведется n раз.

А такое?

#include <iostream>
#include <limits>
using namespace std;

int main()
{
    int i;
    bool good = true;
    do
    {
        cout << "Enter [i]: ";
        cin >> i ;
        if ( !(good=cin.good()) )
            cout << "Fatal input error!" << endl;
        cin.clear() ;
        cin.ignore( numeric_limits<streamsize>::max() , '\n') ;
    }while( !good );

    cout << "You enter: " << i << endl;
    return 0;
}

Если ввести сначала символы, то сообщение об ошибке будет выводится вечно, хотя есть восстановление потока и его очистка.

in_avail скорее всего возвращает 0 для синхронизированных потоков. Можно попробовать отрубить синхронизацию:

bool state = std::ios::sync_with_stdio ( false ) ;
//бла-бла-бла
std::ios::sync_with_stdio ( state ) ;

Если ввести сначала число, а потом без пробелов символы( например 12345asd ), сообщение об ошибке не выведется, а в i будет записано 12345( для примера выше ).

ну так считал же число, а дальше уже идут не числовые данные

А такое?

Да, этот код работает. Но я не пойму, в чём его секрет?

UPD

numeric_limits<streamsize>::max()

Это же вроде тоже очистка потока или нет?

Это же вроде тоже очистка потока или нет?

А секрет в том, что, в отличии от in_avail, который может запросто вернуть 0, здесь игнорирование максимального кол-ва символов и вторым параметром еще разделитель.

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

Ответить

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

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

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

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

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

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