С++ getline() не ждет ввода с консоли при вызове несколько раз

Я пытаюсь получить несколько пользовательских параметров ввода из консоли, две строки, два int и double. Соответствующий код, который я пытаюсь использовать, следующий:

#include <string>
#include <iostream>
using namespace std;

// ...

string inputString;
unsigned int inputUInt;
double inputDouble;

// ...

cout << "Title: "; 
getline(cin, inputString);
tempDVD.setTitle(inputString);

cout << "Category: "; 
getline(cin, inputString);
tempDVD.setCategory(inputString);

cout << "Duration (minutes): "; 
cin >> inputUInt; 
tempDVD.setDuration(inputUInt);

cout << "Year: "; 
cin >> inputUInt; 
tempDVD.setYear(inputUInt);

cout << "Price: $"; 
cin >> inputDouble; 
tempDVD.setPrice(inputDouble);

Однако при запуске программы вместо ожидания ввода первой входной строки код не останавливается до второго вызова getline(). Таким образом, вывод консоли выглядит следующим образом:

Название: Категория:

с курсором, появляющимся после категории. Если я сейчас ввожу, программа затем переходит к вводу года, не позволяя мне вводить несколько строк. Что здесь происходит?

Ответы

Ответ 1

Проблема заключается в том, что вы смешиваете вызовы с getline() с помощью оператора → .

Помните, что оператор → игнорирует ведущее белое пространство, поэтому будет верно продолжаться по границам строк. Но перестает читать после того, как вход успешно восстановлен и, таким образом, не проглотит завершающие символы "\n". Таким образом, если вы используете getline() после → , вы обычно ошибаетесь, если не будете осторожны (сначала удалите символ "\n", который не был прочитан).

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

Если все числа (или объекты, которые хорошо играют с оператором → ), то просто используйте оператор → (строка примечаний - это единственный фундаментальный тип, который не является симметричным с вводом/выводом (т.е. не играет красиво)).

Если вход содержит строки или комбинацию вещей, для которых потребуется getline(), используйте только getline() и проанализируйте номер из строки.

std::getline(std::cin, line);
std::stringstream  linestream(line);

int  value;
linestream >> value;

// Or if you have boost:
std::getline(std::cin, line);
int  value = boost::lexical_cast<int>(line);

Ответ 2

Вам нужно очистить входной буфер. Это можно сделать с помощью cin.clear(); cin.sync();.

Ответ 3

Вы можете использовать

cin.ignore();

или как упомянутое использование @kernald

cin.clear();
cin.sync();

перед использованием getline()

Ответ 4

Используйте cin.clear(), как указано и, используйте правильную обработку ошибок:

    cin.clear();
    cin.sync();

    cout << "Title: "; 
    if (!getline(cin, inputString))  exit 255;
    tempDVD.setTitle(inputString);

    cout << "Category: "; 
    if (!getline(cin, inputString))  exit 255;
    tempDVD.setCategory(inputString);

    cout << "Duration (minutes): "; 
    if (!(cin >> inputUInt)) exit 255; 
    tempDVD.setDuration(inputUInt);

    cout << "Year: "; 
    if (!(cin >> inputUInt)) exit 255; 
    tempDVD.setYear(inputUInt);

    cout << "Price: $"; 
    if (!(cin >> inputDouble)) exit 255; 
    tempDVD.setPrice(inputDouble);

Ответ 5

Если пользователь вводит пробел перед \n в предыдущем cin перед getline, только игнорировать себя будет недостаточно, поэтому вам придется использовать этот код вместо ignore(). Например, 12345\t\n больше не будет работать. Все необработанные символы должны игнорироваться.

#include <limits>
cin.ignore(numeric_limits<streamsize>::max(), '\n');

Используйте это между cin и getline.

Ответ 6

Смешение getline() с входными потоками, как правило, плохое. Теоретически можно вручную обрабатывать грязные буферы, оставшиеся с помощью потоков, но это ненужная боль, которую обязательно следует избегать.

Вам лучше использовать библиотеку консоли, чтобы захватить ваш вход, таким образом, грязная работа может быть абстрагирована для вас.

Взгляните на TinyCon. Вы можете просто использовать статический метод tinyConsole:: getLine() вместо ваших вызовов getline и stream, и вы можете использовать его столько раз, сколько захотите.

Вы можете найти информацию здесь: https://sourceforge.net/projects/tinycon/

Ответ 7

cin.sync(); используйте это вместо cin.ignore( работает лучше всего.