istringstream игнорирует первую букву

Я пытаюсь получить доступ к разным словам в строке, используя std::istringstream, и я также делаю это с несколькими тестовыми примерами.

int t;
cin>>t;
while(t--)
{
     string arr;
     cin.ignore();
     getline(cin,arr);
     istringstream iss(arr);
     string word;
     while(iss>>word)
     {
          cout<<word;
      }
 }

Для первого теста все идеально (то есть выводит правильные слова). Но для каждого последующего теста первая буква первого слова пропускается.

Пример:

Ввод:


4

эй там эй

hi hi hi

меня зовут xyz

девушка ест банан

И я получаю:

Выход:


эй там эй

i hi hi

тебя зовут xyz

ирл ест банан

Может ли кто-нибудь предложить мне, что делать и почему возникает эта ошибка?


person amora    schedule 29.05.2016    source источник
comment
Не могли бы вы предоставить минимально воспроизводимый пример, пожалуйста. Что такое arr на самом деле?   -  person πάντα ῥεῖ    schedule 29.05.2016
comment
Да, я сделал, большое спасибо, что указали на это.   -  person amora    schedule 29.05.2016
comment
Переместите cin.ignore() перед циклом. Также попытайтесь выяснить, что он на самом деле делает,   -  person n. 1.8e9-where's-my-share m.    schedule 29.05.2016


Ответы (3)


Ваша проблема в том, что форматированный ввод, т. Е. Что-то вроде in >> value, обычно пропускает начальные пробелы перед попыткой чтения. С другой стороны, неформатированный ввод не пропускает начальные пробелы. С std::cin.ignore(); в вашем цикле вы делаете предположение, что std::getline(std::cin, arr) оставит новую строку во входных данных, как это делает ввод t. Это не так. std::getline() извлекает и сохраняет все символы до первой новой строки, где она останавливается, по-прежнему извлекая новую строку. Итак, вы бы удалили cin.ignore(); из цикла.

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

  1. std::cin >> std::ws; пропускает все начальные пробелы. Это может включать несколько новых строк и пробелов в начале строки. Пропускать их не всегда желательно.
  2. std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); игнорирует все символы до первой новой строки включительно. Это позволило бы следовать пустым строкам, а также строкам, начинающимся с начального пробела.
person Dietmar Kühl    schedule 29.05.2016

Эта строка является виновником: cin.ignore();.

Когда std::basic_istream::ignore вызывается без каких-либо аргументов, он игнорирует ровно 1 символ.

В вашем случае std::cin.ignore() будет игнорировать первую букву, но не для первого теста, потому что в этот момент std::cin пусто, поэтому игнорировать нечего. Но тогда в std::cin есть другие слова, поэтому он игнорирует 1 символ из первого слова.

person Rakete1111    schedule 29.05.2016
comment
Я думаю, что в первом случае есть что игнорировать, то есть символ новой строки, но в следующий раз пользовательский ввод уже будет пропущен на один символ к тому времени, когда он доберется до оператора getline. - person Biruk Abebe; 29.05.2016

Согласно документации std::basic_istream::ignore:

Извлекает и отбрасывает символы из входного потока до разделителя включительно. игнорировать ведет себя как UnformattedInputFunction

Стоит отметить, что std::basic_istream::ignore будет блокировать и ждать ввода пользователя, если в потоке нечего игнорировать.

Имея это в виду, давайте разберем, что делает ваш код:

  1. при первом вызове этой функции в цикле она будет игнорировать символ новой строки, который все еще находится в буфере из предыдущей операции cin>>t. Затем статус getline будет ждать и читать строку от пользователя.
  2. В следующий раз, поскольку в буфере нет ничего, что можно было бы игнорировать (поскольку std::getline не оставляет символ новой строки в буфере), он будет блокироваться и ждать ввода для игнорирования. Таким образом, в следующий раз, когда программа блокируется и ожидает ввода, это происходит из-за функции ignore(), а не функции getline, как вы надеялись, и в момент, когда вы вводите ввод (т.е. второй тестовый пример), один символ из ввода будет игнорироваться.
  3. Следующая функция getline не будет блокироваться, так как в буфере есть что-то, оставленное предыдущей функцией ignore после того, как она проигнорировала первый символ ввода, поэтому getline прочитает оставшуюся строку, которая окажется короче на один символ.
  4. Процесс продолжается с шага 2, пока ваш цикл не завершится.

int t;
cin>>t;//this leaves new line character in the buffer
while(t--)
{
    string arr;
    cin.ignore();//this will ignore one character from the buffer,so the first time 
                //it will ignore the new line character from the previous cin input
               //but next time it will block and wait for input to ignore
    getline(cin,arr);//this will not block if there is something in the buffer 
                    //to read
     ...
}

Решение состоит в том, чтобы переместить оператор ignore из цикла рядом с вашим оператором cin>>t. В этом случае также лучше написать ignore(INT_MAX,'\n');. Вы также можете прочитать этот ответ, чтобы узнать, когда и как использовать ignore.

person Biruk Abebe    schedule 29.05.2016