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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
ququ_smile
1 / 1 / 0
Регистрация: 28.01.2013
Сообщений: 153
#1

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

23.07.2013, 00:27. Просмотров 874. Ответов 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";
}
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
23.07.2013, 00:27     Охота на ошибки, при неправильном вводе
Посмотрите здесь:
ошибка при вводе в неправильном формате C++
C++ Устранение возможной ошибки пользователя при вводе
Как реализовать вывод ошибки при вводе пользователем символов? C++
Почему при вводе числа программа работает нормально, а при вводе буквы уходит в бесконечный цикл? C++
C++ Как организовать повтор ввода при неправильном ответе
C++ Составить программу, которая при вводе символа с клавиатуры выво-дит "латинская буква" при вводе латинской буквы и "не латинская бук-ва" во всех остал
Выведение ошибки на экран ри вводе одинаковых чисел C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
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
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
38 / 32 / 1
Регистрация: 01.06.2013
Сообщений: 117
23.07.2013, 01:29     Охота на ошибки, при неправильном вводе #6
ququ_smile,
Цитата Сообщение от ququ_smile Посмотреть сообщение
Функция же clear() “очищает” состояние потока
, но не сам поток.

Не по теме:

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

Belfegor
Ghost
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
5416 / 4812 / 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
38 / 32 / 1
Регистрация: 01.06.2013
Сообщений: 117
23.07.2013, 02:15     Охота на ошибки, при неправильном вводе #9
alsav22, спасибо большое.
обязательно возьму на заметку!
ForEveR
В астрале
Эксперт С++
7969 / 4731 / 320
Регистрация: 24.06.2010
Сообщений: 10,539
Завершенные тесты: 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
:)
Эксперт С++
4392 / 3235 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
23.07.2013, 11:41     Охота на ошибки, при неправильном вводе #11
ForEveR, причем ignore() должен работать быстрее.
ForEveR
В астрале
Эксперт С++
7969 / 4731 / 320
Регистрация: 24.06.2010
Сообщений: 10,539
Завершенные тесты: 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
:)
Эксперт С++
4392 / 3235 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
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
:)
Эксперт С++
4392 / 3235 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
23.07.2013, 13:00     Охота на ошибки, при неправильном вводе #15
alsav22, ну дело не только в скорости. Просто всё таки лучше, когда само название функции говорит о выполняемых действиях.
alsav22
5416 / 4812 / 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
В астрале
Эксперт С++
7969 / 4731 / 320
Регистрация: 24.06.2010
Сообщений: 10,539
Завершенные тесты: 3
23.07.2013, 13:13     Охота на ошибки, при неправильном вводе #17
alsav22, std::numeric_limits<std::streamsize>::max() забыли первым параметром же.
alsav22
5416 / 4812 / 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
В астрале
Эксперт С++
7969 / 4731 / 320
Регистрация: 24.06.2010
Сообщений: 10,539
Завершенные тесты: 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++
Дебри указателей - охота на память C++
C++ Ошибка при вводе
Зацикливается при вводе C++
C++ Ошибка с массивом: программа при вводе "ступорится" при нажатии клавиши Enter

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

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

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