Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 5.00/6: Рейтинг темы: голосов - 6, средняя оценка - 5.00
ququ_smile
1 / 1 / 3
Регистрация: 28.01.2013
Сообщений: 169
1

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

23.07.2013, 00:27. Просмотров 1133. Ответов 19
Метки нет (Все метки)

В общем проблема такая. Если есть переменная типа 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";
}
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
23.07.2013, 00:27
Ответы с готовыми решениями:

Ошибка при вводе в неправильном формате
Доброго всем времени суток! Есть код, очень простенький. И есть баг: если пользователь вводит...

Нужно сделать так чтобы при неправильном вводе программа не прекращала работу, а предлагала заново ввести значение N
Вот собственно сам код #include&lt;ctime&gt; #include&lt;iostream&gt; using namespace std; int N,...

Уведомление о неправильном вводе
Доброго времени суток. Помогите, пожалуйста добавить защиту от ввода недопустимых символов. Здесь...

Устранение возможной ошибки пользователя при вводе
Здравствуйте! Есть участок кода (если понадобится скину весь код), в самом начале есть выбор пункта...

Как реализовать вывод ошибки при вводе пользователем символов?
Допустим есть программа выполняющая простейшую операцию, например, нахождение суммы двух целых...

19
Denisqwwq
38 / 32 / 7
Регистрация: 01.06.2013
Сообщений: 117
23.07.2013, 00:39 2
C++
1
 std::cin.sync();
Добавлено через 6 минут
после
C++
1
std::cin.clear();
1
ququ_smile
1 / 1 / 3
Регистрация: 28.01.2013
Сообщений: 169
23.07.2013, 00:46  [ТС] 3
Спасибо. А вы не можете наглядно объяснить в чем отличие между clear() и sync() ? А то из объяснения, которое я нашел в интернете мне ничего не понятно (сброс битов ошибок входного стандартного потока). Как это понимать?
0
Denisqwwq
38 / 32 / 7
Регистрация: 01.06.2013
Сообщений: 117
23.07.2013, 01:06 4
ququ_smile, http://cppstudy.wordpress.com/2009/03/27/cin-get-and-co/
вот, более доступно написано.
0
23.07.2013, 01:06
ququ_smile
1 / 1 / 3
Регистрация: 28.01.2013
Сообщений: 169
23.07.2013, 01:20  [ТС] 5
"Эта функция восстанавливает поток, если он по какой-либо причине оказался в ошибочном состоянии. Например, из потока пытались прочитать число, а там в это время находились буквы. В этом случае, поток переводится в состояние отказа, и дальнейшие операции с ним неосуществимы. В том числе и cin.get(). Функция же clear() “очищает” состояние потока, делая его вновь веселым и работоспособным."


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

Не по теме:

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

0
Belfegor
Ghost
173 / 173 / 40
Регистрация: 16.09.2012
Сообщений: 526
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;
}
0
alsav22
5453 / 4848 / 831
Регистрация: 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;
    }
2
Denisqwwq
38 / 32 / 7
Регистрация: 01.06.2013
Сообщений: 117
23.07.2013, 02:15 9
alsav22, спасибо большое.
обязательно возьму на заметку!
0
ForEveR
В астрале
Эксперт С++
8007 / 4764 / 654
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 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');
1
Tulosba
:)
Эксперт С++
4751 / 3245 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
23.07.2013, 11:41 11
ForEveR, причем ignore() должен работать быстрее.
0
ForEveR
В астрале
Эксперт С++
8007 / 4764 / 654
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 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;
                }
            }
0
Tulosba
:)
Эксперт С++
4751 / 3245 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
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() каждый раз.
0
alsav22
23.07.2013, 12:57
  #14

Не по теме:

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

0
Tulosba
:)
Эксперт С++
4751 / 3245 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
23.07.2013, 13:00 15
alsav22, ну дело не только в скорости. Просто всё таки лучше, когда само название функции говорит о выполняемых действиях.
1
alsav22
5453 / 4848 / 831
Регистрация: 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;
}
0
ForEveR
В астрале
Эксперт С++
8007 / 4764 / 654
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
23.07.2013, 13:13 17
alsav22, std::numeric_limits<std::streamsize>::max() забыли первым параметром же.
0
alsav22
5453 / 4848 / 831
Регистрация: 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;
}
0
ForEveR
В астрале
Эксперт С++
8007 / 4764 / 654
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
23.07.2013, 13:39 19
alsav22, Да с чего это будет лучше? Вам же уже сказали, что лучше пользоваться тем что есть. Есть функция ignore, которая специально предназначнена для игнорирования символов до переданного, этого недостаточно? Не стоит все же писать велосипеды там, где они не нужны.

А насчет первого я согласен конечно, я думал там cin.ignore зовется, извиняюсь.
0
alsav22
5453 / 4848 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
23.07.2013, 15:11 20
Цитата Сообщение от ForEveR Посмотреть сообщение
Да с чего это будет лучше?
Я имел ввиду лучше, по сравнению с моим кодом в 16 посте.
Цитата Сообщение от ForEveR Посмотреть сообщение
Не стоит все же писать велосипеды там, где они не нужны.
С этим не спорю.
0
23.07.2013, 15:11
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
23.07.2013, 15:11

Почему при вводе числа программа работает нормально, а при вводе буквы уходит в бесконечный цикл?
void mainmenu() { cout &lt;&lt; &quot;Введи число&quot; &lt;&lt; endl; cin &gt;&gt; choice; if (choice == 1) { cout &lt;&lt;...

Вывод ошибки при неправильном вводе
Помогите пожалуйста, мне нужно чтобы к примеру при вводе первого числа 0 и второго 0, в конце...

Неполучается чтоб при неправильном вводе воводилась надпись ошибки.
&lt;form action=&quot;#&quot; method=&quot;post&quot;&gt; &lt;span...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru