Выбор вариантов (чистый Си)

Модератор: Модераторы разделов

GenchiK
Сообщения: 27

Выбор вариантов

Сообщение GenchiK »

Всем привет!

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

Помогите решить данную проблему пожалуйста.

Вот функция, если я введу неправильную цифру, то всё правильно обработается и попросит ввести заново, но если я введу знак/строку то всё циклится....:
Как исправить проблему с зацикливанием? Я так понимаю всё дело в типе... целочисленному типу присваивают строку... или нет? и как решить эту проблему?

Код: Выделить всё

int select() {

    int option;

    printf("\n* Введите номер действия:: ");
    scanf("%i" , &option );

    while( ( option>'a' && option<'z' ) || ( option<=0 || option>5 ) ) {

        printf("\n* Введите номер действия:: ");
        scanf("%i" , &option );

    }

    switch( option ) {
        //case 1: search(); break;
        case 2: list(); break;
        case 3: addWord(); break;
        //case 4: deleteWord(); break;
        case 5: exit; break;

        default: select(); break;
    }
}
Спасибо сказали:
GenchiK
Сообщения: 27

Re: Выбор вариантов

Сообщение GenchiK »

Я что-то туплю.... вроде всё просто решаться должно... видня я устал :)
Спасибо сказали:
Аватара пользователя
Фантом
Сообщения: 460
ОС: openSUSE

Re: Выбор вариантов

Сообщение Фантом »

GenchiK писал(а):
29.01.2011 01:12
Как исправить проблему с зацикливанием? Я так понимаю всё дело в типе... целочисленному типу присваивают строку... или нет? и как решить эту проблему?

Нет, дело как раз в том, что строку ему не присваивают. ;) scanf читает все, что идет с клавиатуры, а это не только собственно введенный символ, но и перевод строки и т.д. (кстати, у Вас локаль - utf8?). В итоге следующему scanf'у достаются ошметки предыдущего ввода и начинается кавардак.

Чтобы этого не происходило, надо чистить буфер ввода перед очередным scanf'ом. Например, переписав цикл while так:

Код: Выделить всё

while( option<=0 || option>5 )
{
  printf("\n* Введите номер действия:: ");
  __fpurge(stdin);
  scanf("%i" , &option );
}

Второй возможный вариант - делать строго посимвольное чтение (используя getc()).

Кстати, условие про 'a' и 'z' из шапки цикла можно убрать (что я и сделал), оно все равно ни на что не влияет (при его истинности автоматически будет истинными один из вариантов второй половины условия).
Спасибо сказали:
GenchiK
Сообщения: 27

Re: Выбор вариантов

Сообщение GenchiK »

Спасибо, огромное Вам!)))Всё работает! Всё супер! Только я не понял команды __fpurge(stdin), у меня пишет что незадекларирована такая функция...Это навеное из С++?
Я воспользовался fflush(stdin).

Ещё раз спасибо!.

Фантом писал(а):
29.01.2011 02:50
(кстати, у Вас локаль - utf8?)


Нет, я специально для форума написал на русском)
Спасибо сказали:
Аватара пользователя
Фантом
Сообщения: 460
ОС: openSUSE

Re: Выбор вариантов

Сообщение Фантом »

GenchiK писал(а):
29.01.2011 02:59
Только я не понял команды __fpurge(stdin), у меня пишет что незадекларирована такая функция...Это навеное из С++?

А, да, она действительно не совсем стандартна (хотя и не из C++). Впрочем, GCC ее понимает.

Кстати, fflush() для этой цели тоже формально не годится (по стандарту она работает только с потоками вывода), хотя многие компиляторы и в таком виде ее "съедают".

Если уж пытаться сделать все идеально честно, то сработает такая штука - вместо __fpurge/fflush вставить такое:

Код: Выделить всё

scanf("%*[^\n]");
scanf("%*c");

Требуемый результат получится, но это уже как-то не очень красиво на вид. :crazy:
Спасибо сказали:
GenchiK
Сообщения: 27

Re: Выбор вариантов

Сообщение GenchiK »

А не объясните смысл этих строк?)))))

Я так понимаю это регулярные выражения, первая строчка съедает переход строки, а вторая исходя из логики c(char) съедает буквы?))))
Спасибо сказали:
Аватара пользователя
Фантом
Сообщения: 460
ОС: openSUSE

Re: Выбор вариантов

Сообщение Фантом »

GenchiK писал(а):
29.01.2011 03:26
А не объясните смысл этих строк?)))))

Я так понимаю это регулярные выражения, первая строчка съедает переход строки, а вторая исходя из логики c(char) съедает буквы?))))

Почти, но наоборот. :) Первая строчка съедает все, кроме перевода строки (^ - это как раз признак "принимать все, кроме"), и останавливается, добравшись до перевода, а вторая доедает последний оставшийся символ (которым, собственно, перевод строки и является). Звездочка в формате означает, что введенные таким образом символы никуда не записываются.
Спасибо сказали:
GenchiK
Сообщения: 27

Re: Выбор вариантов

Сообщение GenchiK »

Ух ты !))))Спасибо!))) и респект))):)
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Выбор вариантов

Сообщение NickLion »

Уточнения и замечания. Поведение fflush, строго говоря, определяется не компилятором, а реализацией стандартной библиотеки C. В стандарте POSIX поведение fflush описано для потоков вывода или обновления, но в реализации GNU/Linux прямо в документации есть уточнение и для потоков ввода. Также работает и реализия под Windows. Как в случае FreeBSD, MacOSX - не знаю, но судя по докам макоси - там надо использовать fpurge.
Замечание 2. Можно тот код запихнуть в один scanf - scanf("%*[^\n]%*c"); имхо, так как-то проще :)
Спасибо сказали:
GenchiK
Сообщения: 27

Re: Выбор вариантов

Сообщение GenchiK »

Спасибо!))))Очень позновательно))) :) я всё таки оставил fflush();
Спасибо сказали: