стандартный поток ввода cin не может запрашивать ввод

1 #include<iostream>
  2 using namespace std;
  3 
  4 int main()
  5 {
  6     const double yen_to_euro=0.007215;
  7     const double euro_to_dollar=1.12;
  8     char currency;
  9     double x;
 10 
 11     while(currency!='q')
 12     {
 13         cout << "enter currency and unit(y , e, or d)";
 14         cin >> x >>currency;
 15 
 16         switch(currency){
 17 
 18             case 'y':
 19                 cout <<"euro:"<< x*yen_to_euro<<" dollar:"<<x*yen_to_euro*euro_to_dollar<<'\n';
 20                 break;
 21             case 'e':
 22                 cout <<"yen:"<< (x*(1.0/yen_to_euro))<<" dollar:"<<(x*euro_to_dollar)<<'\n';
 23                 break;
 24             case 'd':
 25                 cout <<" yen:"<< x*(1.0/yen_to_euro)*(1.0/euro_to_dollar)<<" euro:"<<x*(1.0/euro_to_dollar)<<'\n';
 26                 break;
 27             case 'q':
 28                 currency='q';
 29                 break;
 30             default:
 31                 cout << "invalid";
 32                 break;
 33 
 34         }
 35 
 36     }
 37 
 38 
 39 }
~             

Предполагаемая функция приведенного выше кода заключается в конвертации выбранной валюты (y для японской иены, e для евро и d для доллара США) в другие валюты.

Например, если я хочу конвертировать в 12 японских иен, я бы ввел:

12y

который затем программа будет выводить

евро: 0,08658 доллар: 0,0969696

Однако, если бы я ввел 12e, я бы получил бесконечный цикл. Дважды проверив код, логических ошибок вроде бы нет. Тем не менее, я чувствую, что источник проблемы связан с cin в строке 14, потому что если я возьму сумму x и тип валюты отдельно, вот так:

cin>> x;
cin>> currency;

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

Более того, почему он так себя ведет? Это необычное поведение прохождения бесконечного цикла происходит только тогда, когда я ввожу e для евро и q для выхода.


person Community    schedule 12.08.2015    source источник
comment
Символ 'e' сбивает синтаксический анализатор, заставляя его думать, что вы пытаетесь передать значение в экспоненциальном представлении. В большинстве случаев синтаксический анализатор сдастся, как только дойдет до нечислового символа, и вернет значение, которое он проанализировал до сих пор. Однако в этом случае он читает 'e' как часть числа, переключается в научный режим, а затем решает, что число неправильно отформатировано, и терпит неудачу (вы можете проверить cin.good(), чтобы проверить эту и другие ошибки синтаксического анализа).   -  person Wug    schedule 13.08.2015


Ответы (3)


12e интерпретируется как начало числа с плавающей запятой, например 12e03. Но конец отсутствует, поэтому ваш поток ставится на ошибку (failbit). Это состояние приводит к сбою всех последующих входных данных до тех пор, пока состояние сбоя не будет очищено.

У вас может быть внутренний цикл, который проверяет такие ошибки форматирования:

while (...) {
     ...
     while ( (cin >> x >> currency).fail() && !cin.eof()) { // loops as long as there's input and it's invalid
         cout << "invalid format";
         cin.clear(); 
     }
     if (cin.eof())  // if there's no longer input stop looping
         break; 
     ...
 }

демонстрация

Обратите внимание, что вы должны инициализировать currency чем-то отличным от 'q', если хотите убедиться, что ваш цикл выполняется при любых обстоятельствах.

Кстати, если вы введете 12 e (с пробелом), 12 будет интерпретировано как число и будет помещено в x, а e в валюту, как вы и ожидали.

person Christophe    schedule 12.08.2015

Как объясняется в других ответах, 12e относится к научной записи чисел с плавающей запятой, и, следовательно, currency не хранит «e».

Чтобы получить ввод в одну строку без пробела, вы должны использовать std::getline, а затем проанализировать входную строку.

Поскольку вы знаете, что последний символ всегда указывает на валюту, передние символы можно преобразовать в число с помощью std::stoi.

person rs_    schedule 12.08.2015

Замените cin >> x >>currency; на

    try{
      std::string myLine;
      std::getline (std::cin, myLine); // store line into myLine.
      currency = myLine.back(); // get last character from line.
      myLine.pop_back(); // remove last character from myLine.
      x = std::stod(myLine); // try to conver the rest of the string to a double.
    }
    catch (...) {
      //The user typed in something invalid.
      currency= 'i';
    }

Также не забудьте #include <string>

Обратите внимание, что это решение предполагает, что вы используете C11.

person Kevin Wheeler    schedule 12.08.2015
comment
Причина, по которой он зацикливается навсегда, заключается в том, что «12e» — это неправильно отформатированное число с плавающей запятой в экспоненциальном представлении, и оно устанавливает бит отказа. После этого каждая попытка прочитать ввод из потока прерывается, потому что бит ошибки никогда не сбрасывается, а значения, в которые он пытается прочитать, никогда не изменяются. - person Wug; 13.08.2015