2010-12-27 1 views
2

я делаю консольного приложения, я передаю целое в приложение и работает нормально, но если я передаю письмо, он сходит с ума,C++ проверить количество и остановить пейзажный цикл

int opt=0; 
std::cout<<"Pick lang:"<<'\n'; 
std::cout<<"1.[es-ES]:"<<'\n'; 
std::cout<<"2.[en-US]:"<<'\n'; 
std::cin >> opt; 

while(opt<1 || opt>2) 
{ 
    std::cout<<"\nERROR!"<<'\n'; 
    std::cout<<"Pick lang again:"<<'\n'; 
    std::cout<<"1.[es-ES]:"<<'\n'; 
    std::cout<<"2.[en-US]:"<<'\n'; 
    std::cin >> opt; 
} 

Я пытался использовать isdigit(), но получаю тот же результат. Спасибо

+0

Когда вы говорите, «передать письмо», вы имеете в виду вы читаете 'char'? Или вы хотите ввести письмо при запуске вышеуказанного кода? – marcog

+1

Посмотрите, поможет ли это. http://stackoverflow.com/questions/4342068/c-infinite-loop-with-a-simple-menu-selection/4342247#4342247 –

+0

да, я читаю символ, но cin ждет int –

ответ

7

После выполнения удаления cin >>, вы хотите проверить, хорош ли поток cin или нет. Если вы ожидаете, что cin выберет номер, но вместо этого он получит что-то другое, например. как письмо, тогда поток будет настроен на плохое состояние, и именно поэтому вы видите, что он «сходит с ума».

Что вам нужно сделать после ввода, проверьте, хорош ли cin. Если он находится в плохом состоянии, вам нужно очистить его флаги, а затем удалить из данных нежелательных данных в потоке. Если вы этого не сделаете, то последующее использование cin просто не сработает.

Принимая фрагмент кода, например, вы можете изменить его на что-то вроде этого:

int opt = 0; 
bool inputGood = false; 

do 
{ 
    std::cout << "Pick lang again:" << '\n'; 
    std::cout << "1.[es-ES]:" << '\n'; 
    std::cout << "2.[en-US]:" << '\n'; 
    inputGood = std::cin >> opt; 
    if(!inputGood) 
    { 
     std::cout << "\nERROR! Invalid choice." << '\n'; 
     cin.clear(); 
     while(cin.get() != '\n'); 
    } 
}while(!inputGood || opt < 1 || opt > 2); 

Edit: возгласы незначительная ошибка в обработке ошибок CIN. Исправлено и должно работать сейчас. :)

1

При вставке письмо это происходит:

  1. operator>> извлекает символы из потока и попытаться преобразовать их в ряд;
  2. сбой при преобразовании, поэтому он устанавливает состояние потока ios::failbit и возвращает; opt, вероятно, нетронутый (стандарт делегирует этот материал библиотеке локалей, которая является зоной C++, которую я никогда не понимал - для достаточно храбрых, это в §22.2.2.1.2);
  3. с тех пор, как он вернулся и (возможно) opt оставлен как есть, цикл продолжается;
  4. , когда выполнение возвращается к std::cin >> opt;, operator>> видит, что состояние по-прежнему ios::failbit, поэтому оно даже не пытается извлечь что-либо;
  5. Гото 3.

Чтобы устранить эту проблему, вы должны очистить состояние ошибки и устранить «неправильные» символы из входного буфера. Поскольку вы, вероятно, не хотите добавлять весь этот код к каждому cin>>, полезно создать функцию для решения этой общей проблемы; лично я создал этот маленький заголовок (AcquireInput.hpp), которая доказала свою полезность во много раз:

#ifndef ACQUIREINPUT_HPP_INCLUDED 
#define ACQUIREINPUT_HPP_INCLUDED 

#include <iosfwd> 
#include <limits> 
#include <string> 

    template<typename InType> void AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString, InType & Result) 
    { 
     do 
     { 
      Os<<Prompt.c_str(); 
      if(Is.fail()) 
      { 
       Is.clear(); 
       Is.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 
      } 
      Is>>Result; 
      if(Is.fail()) 
       Os<<FailString.c_str(); 
     } while(Is.fail()); 
    } 

    template<typename InType> InType AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString) 
    { 
     InType temp; 
     AcquireInput(Os,Is,Prompt,FailString,temp); 
     return temp; 
    } 

    /* Usage example: 

     //1st overload 
     int AnInteger; 
     AcquireInput(cout,cin,"Please insert an integer: ","Invalid value.\n",AnInteger); 

     //2nd overload (more convenient, in this case) 
     int AnInteger=AcquireInput(cout,cin, "Please insert an integer: ","Invalid value.\n"); 
    */ 

#endif 
2

Проблема заключается в том, что вызов std::cin >> opt не в состоянии разобрать символ и возвращает немедленно (без потребления буфера), то он находит то же содержимое и ошибка ....

Вы должны проверить результат операции и отреагировать на нее. Одной из возможностей было бы проверить бит сбоя (std::cin.fail()) и провалить всю операцию или потреблять части буфера (возможно, один символ, может быть, больше, в зависимости от того, как вы хотите, чтобы приложение себя вел).

Самое простое, что, вероятно, будет не читает в ряд, а символ, а затем по сравнению с ожидаемым характером:

char opt = 0; 
do { 
    // prompt user for input 
    if (! (std::cin >> opt)) { 
     // io error, report and bail out 
     break; 
    } 
} while (opt != '0' && opt != '1'); 
+0

I Думаете, вы имеете в виду 'opt! = '1' || opt! = '2''. opt не может быть одновременно «0» и «1», не так ли? ': P' – Muggen

+0

@Muggen:' opt! = '0' || opt! = '1'' эквивалентно 'true', так как если он' '0'', он не может быть' '1'' и наоборот (т. е. он всегда отличен от' 1' или отличается от ' 0''). Когда 'opt' является либо' '0'', либо '' 1'', ​​условие цикла должно быть «ложным» ... или, может быть, я смущен? –

+0

@ Давид, никогда не ошибаюсь. Я вижу, что ты сделал сейчас. – Muggen

1

Чтение в цифрах напрямую проблематично

Если std :: cin представлен с вводом его не может обрабатываться, std :: cin переходит в состояние «fail» . Вход в него не может процесс остается во входном потоке.

Все входные будут игнорироваться станд :: CIN до «глючить» состояние очищается: зЬй :: cin.clear()

Процедура, которая считывает ряд непосредственно следует:

  1. Читайте в числа

  2. Проверьте, что входной поток остается в силе

  3. Если входной поток не хорошо (! Станд :: CIN)

    1. Вызов станд :: cin.clear(), чтобы принять поток из «строя» состоянии.
    2. Удалить из потока на входе, который вызвал проблему: зЬй :: cin.ignore (...)
    3. Получить вход снова в случае необходимости или иначе обработать ошибку

подробнее здесь: http://www.augustcouncil.com/~tgibson/tutorial/iotips.html

Смежные вопросы