std::getline не работает внутри цикла for
Вопрос
Я пытаюсь собрать введенные пользователем данные в строковую переменную, которая принимает пробелы в течение определенного периода времени.
Поскольку обычный cin >> str
не принимает пробелы, поэтому я бы использовал std::getline из <string>
Вот мой код:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
int n;
cin >> n;
for(int i = 0; i < n; i++)
{
string local;
getline(cin, local); // This simply does not work. Just skipped without a reason.
//............................
}
//............................
return 0;
}
Есть идеи?
Решение
Вы можете понять, почему это не удается, если выведете то, что сохранили в local
(кстати, это неудачное имя переменной: P):
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
int n;
cin >> n;
for(int i = 0; i < n; i++)
{
string local;
getline(cin, local);
std::cout << "> " << local << std::endl;
}
//............................
return 0;
}
Вы увидите, что он печатает новую строку после >
сразу после ввода номера.Затем он переходит к вводу остальных.
Это потому что getline
дает вам пустую строку, оставшуюся после ввода вашего номера.(Он считывает номер, но видимо не удаляет \n
, так что у вас останется пустая строка.) Сначала вам нужно избавиться от оставшихся пробелов:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
int n;
cin >> n;
cin >> ws; // stream out any whitespace
for(int i = 0; i < n; i++)
{
string local;
getline(cin, local);
std::cout << "> " << local << std::endl;
}
//............................
return 0;
}
Это работает, как и ожидалось.
Не по теме, возможно, это было только для фрагмента, но код, как правило, более читабельно, если у вас его нет using namespace std;
.Это противоречит цели пространств имен.Я подозреваю, что это было только для публикации здесь.
Другие советы
Объявить персонажа садись в карету вернитесь после того, как вы ввели номер.char ws;int n;cin>>n;ws=cin.get();
Это решит проблему.
С использованием
cin>>ws
вместоws=cin.get()
, первый символ вашей строки будет помещен в переменнуюws
, вместо того, чтобы просто очистить'\n'
.
Вы нажимаете Enter?Если не получить строку, она ничего не вернет, так как ожидает конца строки...
Я думаю, ты не читаешь n
правильно, поэтому он конвертируется в ноль.Поскольку 0 не меньше 0, цикл никогда не выполняется.
Я бы добавил немного инструментов:
int n;
cin >> n;
std::cerr << "n was read as: " << n << "\n"; // <- added instrumentation
for // ...
- Правильно ли инициализируется входной параметр n?
- Похоже, вы ничего не делаете с getline.Это то, чего ты хочешь?
- getline возвращает ссылку на istream.Имеет ли значение тот факт, что вы роняете его на землю?
На каком компиляторе вы это пробовали?Я пробовал на VC2008 и все работало нормально.Если бы я скомпилировал тот же код на g++ (GCC) 3.4.2.Это не сработало должным образом.Ниже приведены версии, работающие в обоих компиляторах.В моей среде нет последней версии компилятора g++.
int n;
cin >> n;
string local;
getline(cin, local); // don't need this on VC2008. But need it on g++ 3.4.2.
for (int i = 0; i < n; i++)
{
getline(cin, local);
cout << local;
}
Важный вопрос: «Что вы делаете со строкой, которая дает вам идею, что ввод был пропущен?» Или, точнее, "почему, по вашему мнению, вход был пропущен?"
Если вы используете отладчик, компилировали ли вы с оптимизацией (которая позволяет изменять порядок инструкций)?Я не думаю, что это ваша проблема, но это возможно.
Я думаю, что более вероятно, что строка заполнена, но обрабатывается неправильно.Например, если вы хотите передать входные данные старым функциям C (например, atoi()
), вам нужно будет извлечь строку стиля C (local.c_str()
).
Вы можете напрямую использовать функцию getline в строке, используя разделитель, следующим образом:
#include <iostream>
using namespace std;
int main()
{
string str;
getline(cin,str,'#');
getline(cin,str,'#');
}
вы можете вводить str столько раз, сколько захотите, но здесь применяется одно условие: вам нужно передать '#' (третий аргумент) в качестве разделителя, т.е.Строка будет принимать ввод до тех пор, пока не будет нажата клавиша «#», независимо от символа новой строки.