Форум программистов, компьютерный форум CyberForum.ru

Охота на ошибки, при неправильном вводе - C++

Восстановить пароль Регистрация
 
ququ_smile
1 / 1 / 0
Регистрация: 28.01.2013
Сообщений: 153
23.07.2013, 00:27     Охота на ошибки, при неправильном вводе #1
В общем проблема такая. Если есть переменная типа int, а туда с клавы вводят какой-нибудь символ, то программе это не нравится и она начинает блевать. Т.е. в потоке cin остается кое-что нехорошее, что нужно убрать. Я пытался перехватить эту ошибку и перехватил, однако после этой ошибки программа завершается и загрязненный поток cin остается бесполезным, а мне это не нужно. Я пытался очистить поток функцией std::cin.clear() , но как-то бесполезно. Как мне исцелить этот поток? Вот код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <windows.h>
#include <stdexcept>
 
int main()
try {
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);
    int x;
    while(true)
    {
        std::cout<<"Введите число (int)\n";
        std::cin>>x;
        if(x == 93) break; // Цикл завершается, при вводе 93
        if(!std::cin)
        {
           // throw std::runtime_error("Ошибка, это не число.Поробуйте еще разок\n"); //Ловушка для ошибки
            std::cin.clear();
            std::cout<<"Ошибка, это не число.Поробуйте еще разок\n";
        }
    }
 
    std::cout<<"Если вы читаете это, значит начали выполнятся те инструкции, которые идут после цикла \n";
    return 0;
}
 
catch (std::runtime_error& e)
{
    std::cerr<<e.what()<<std::endl;
}
 
catch(...)
{
    std::cout<<"Другая ошибка : С \n";
}
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Denisqwwq
 Аватар для Denisqwwq
38 / 32 / 1
Регистрация: 01.06.2013
Сообщений: 117
23.07.2013, 00:39     Охота на ошибки, при неправильном вводе #2
C++
1
 std::cin.sync();
Добавлено через 6 минут
после
C++
1
std::cin.clear();
ququ_smile
1 / 1 / 0
Регистрация: 28.01.2013
Сообщений: 153
23.07.2013, 00:46  [ТС]     Охота на ошибки, при неправильном вводе #3
Спасибо. А вы не можете наглядно объяснить в чем отличие между clear() и sync() ? А то из объяснения, которое я нашел в интернете мне ничего не понятно (сброс битов ошибок входного стандартного потока). Как это понимать?
Denisqwwq
 Аватар для Denisqwwq
38 / 32 / 1
Регистрация: 01.06.2013
Сообщений: 117
23.07.2013, 01:06     Охота на ошибки, при неправильном вводе #4
ququ_smile, http://cppstudy.wordpress.com/2009/0...in-get-and-co/
вот, более доступно написано.
ququ_smile
1 / 1 / 0
Регистрация: 28.01.2013
Сообщений: 153
23.07.2013, 01:20  [ТС]     Охота на ошибки, при неправильном вводе #5
"Эта функция восстанавливает поток, если он по какой-либо причине оказался в ошибочном состоянии. Например, из потока пытались прочитать число, а там в это время находились буквы. В этом случае, поток переводится в состояние отказа, и дальнейшие операции с ним неосуществимы. В том числе и cin.get(). Функция же clear() “очищает” состояние потока, делая его вновь веселым и работоспособным."


Написано, что она "очищает" состояния потока, делая его работоспособным. А написал я эту тему, потому-что после этой функции поток не выздоровел.
Denisqwwq
 Аватар для Denisqwwq
38 / 32 / 1
Регистрация: 01.06.2013
Сообщений: 117
23.07.2013, 01:29     Охота на ошибки, при неправильном вводе #6
ququ_smile,
Цитата Сообщение от ququ_smile Посмотреть сообщение
Функция же clear() “очищает” состояние потока
, но не сам поток.

Не по теме:

Вполне возможно, что я ошибаюсь.

Belfegor
Ghost
 Аватар для Belfegor
172 / 172 / 6
Регистрация: 16.09.2012
Сообщений: 524
23.07.2013, 01:31     Охота на ошибки, при неправильном вводе #7
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
 
int main() {
    int n;
    while (true) {
        std::cin >> n;
        if (std::cin.good())
            std::cout << "Ok" << std::endl;
        else {
            std::cout << "Not number" << std::endl;
            break;
        }
    }
    return 0;
}
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
23.07.2013, 02:12     Охота на ошибки, при неправильном вводе #8
Цитата Сообщение от ququ_smile Посмотреть сообщение
Написано, что она "очищает" состояния потока, делая его работоспособным.
При ошибке, в потоке устаналивается один из флагов ошибки (failbit, badbit), невведённое остаётся в потоке. clear() сбрасывает флаги ошибок, поток становится рабочим, но нужно убрать из потока и то, что осталось невведённым.

Добавлено через 19 минут
Цитата Сообщение от Denisqwwq Посмотреть сообщение
std::cin.sync();
sync() не срабатывает в Linux при очистке потока. Почему неясно, но на практике это так. Можно использовать такую конструкцию (будет выход из ввода, если в строке нет посторонних символов (кроме первых пробелов)):

C++
1
2
3
4
5
6
7
8
9
    cout << "Enter the number: " << endl;
    int i;
    while (!(cin >> i) || cin.peek() != '\n')
    {
        cin.clear();
        while (cin.get() != '\n');
        cout << "Error! Retry input\n";
        cout << "Enter the number: " << endl;
    }
Denisqwwq
 Аватар для Denisqwwq
38 / 32 / 1
Регистрация: 01.06.2013
Сообщений: 117
23.07.2013, 02:15     Охота на ошибки, при неправильном вводе #9
alsav22, спасибо большое.
обязательно возьму на заметку!
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
23.07.2013, 11:17     Охота на ошибки, при неправильном вводе #10
alsav22,
C++
1
while (cin.get() != '\n');
==
C++
1
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Tulosba
:)
Эксперт C++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
23.07.2013, 11:41     Охота на ошибки, при неправильном вводе #11
ForEveR, причем ignore() должен работать быстрее.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
23.07.2013, 11:46     Охота на ошибки, при неправильном вводе #12
Tulosba, По-хорошему да. Как-то так это выглядит в libcxx
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
            if (__n == numeric_limits<streamsize>::max())
            {
                while (true)
                {
                    typename traits_type::int_type __i = this->rdbuf()->sbumpc();
                    if (traits_type::eq_int_type(__i, traits_type::eof()))
                    {
                       __err |= ios_base::eofbit;
                       break;
                    }
                    ++__gc_;
                    char_type __ch = traits_type::to_char_type(__i);
                    if (traits_type::eq(__ch, static_cast<char_type>(__dlm)))
                        break;
                }
            }
Tulosba
:)
Эксперт C++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
23.07.2013, 11:57     Охота на ошибки, при неправильном вводе #13
ForEveR, а в VS как-то так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
if (_Ok && 0 < _Count)
            {   // state okay, use facet to extract
            _TRY_IO_BEGIN
            for (; ; )
                {   // get a metacharacter if more room in buffer
                int_type _Meta;
                if (_Count != INT_MAX && --_Count < 0)
                    break;  // buffer full, quit
                else if (_Traits::eq_int_type(_Traits::eof(),
                    _Meta = _Myios::rdbuf()->sbumpc()))
                    {   // end of file, quit
                    _State |= ios_base::eofbit;
                    break;
                    }
                else
                    {   // got a character, count it
                    ++_Chcount;
                    if (_Meta == _Metadelim)
                        break;  // got a delimiter, quit
                    }
                }
            _CATCH_IO_END
            }
Но я бы еще хотел сказать и про sentry-объект, который в случае с ignore() создается и уничтожается один раз, а при вызове get() каждый раз.
alsav22
23.07.2013, 12:57
  #14

Не по теме:

Цитата Сообщение от Tulosba Посмотреть сообщение
причем ignore() должен работать быстрее.
Всё это, конечно, очень важно для строки, например, из 5 символов.

Tulosba
:)
Эксперт C++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
23.07.2013, 13:00     Охота на ошибки, при неправильном вводе #15
alsav22, ну дело не только в скорости. Просто всё таки лучше, когда само название функции говорит о выполняемых действиях.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
23.07.2013, 13:11     Охота на ошибки, при неправильном вводе #16
Согласен.

Добавлено через 9 минут
Тогда так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<iostream>
using namespace std;
 
void ignore(char delim)
{
    while (cin.get() != delim);
}
 
int main()
{
    cout << "Enter the number: " << endl;
    int i;
    while (!(cin >> i) || cin.peek() != '\n')
    {
        cin.clear();
        ignore('\n');
        cout << "Error! Retry input\n";
        cout << "Enter the number: " << endl;
    }
    
    return 0;
}
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
23.07.2013, 13:13     Охота на ошибки, при неправильном вводе #17
alsav22, std::numeric_limits<std::streamsize>::max() забыли первым параметром же.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
23.07.2013, 13:35     Охота на ошибки, при неправильном вводе #18
Цитата Сообщение от ForEveR Посмотреть сообщение
std::numeric_limits<std::streamsize>::max() забыли первым параметром же
По-моему, в данном случае неактуально. Вот так получше будет:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<iostream>
using namespace std;
 
inline void ignore(char delim = '\n')
{
    while (cin.get() != delim);
}
 
int main()
{
    cout << "Enter the number: " << endl;
    int i;
    while (!(cin >> i) || cin.peek() != '\n')
    {
        cin.clear();
        ignore();
        cout << "Error! Retry input\n";
        cout << "Enter the number: " << endl;
    }
    
    return 0;
}
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
23.07.2013, 13:39     Охота на ошибки, при неправильном вводе #19
alsav22, Да с чего это будет лучше? Вам же уже сказали, что лучше пользоваться тем что есть. Есть функция ignore, которая специально предназначнена для игнорирования символов до переданного, этого недостаточно? Не стоит все же писать велосипеды там, где они не нужны.

А насчет первого я согласен конечно, я думал там cin.ignore зовется, извиняюсь.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
23.07.2013, 15:11     Охота на ошибки, при неправильном вводе
Еще ссылки по теме:

C++ Ошибка с массивом: программа при вводе "ступорится" при нажатии клавиши Enter
Кирилица отображается нормально при выводе из программы, но иероглифы при вводе в консоль C++
C++ Устранение возможной ошибки пользователя при вводе

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
23.07.2013, 15:11     Охота на ошибки, при неправильном вводе #20
Цитата Сообщение от ForEveR Посмотреть сообщение
Да с чего это будет лучше?
Я имел ввиду лучше, по сравнению с моим кодом в 16 посте.
Цитата Сообщение от ForEveR Посмотреть сообщение
Не стоит все же писать велосипеды там, где они не нужны.
С этим не спорю.
Yandex
Объявления
23.07.2013, 15:11     Охота на ошибки, при неправильном вводе
Ответ Создать тему
Опции темы

Текущее время: 14:40. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru