Я новичок в Cpp и пытаюсь просмотреть примеры, приведенные в книге «Принципы и практика программирования с использованием С++» (2-е издание).
Для дальнейшего справки я говорю о «4.6.4 Текстовый пример», где предложение нужно взять в качестве входных данных и построить словарь слов (после сортировки).
Пример, который был упомянут, был похож на приведенный ниже.
// simple dictionary: list of sorted words
int main()
{
vector<string> words;
for(string temp; cin>>temp; ) // read whitespace-separated words
words.push_back(temp); // put into vector
cout << "Number of words: " << words.size() << '\n';
sort(words); // sort the words
for (int i = 0; i<words.size(); ++i)
if (i==0 || words[i–1]!=words[i]) // is this a new word?
cout << words[i] << "\n";
}
В приведенном выше образце кода строка номер 5 (в выражении цикла for) cin >> temp не имеет для меня смысла. Почему? После запуска кода появилась консоль, и я начал вводить предложение с парой слов, и даже после нажатия ввода я не смог завершить строку и перейти к следующей строке? Как завершить ввод здесь?
В настоящее время поток не может прочитать, чтобы выйти из цикла. При чтении в std::string
это довольно сложно сделать без закрытия входного потока. В зависимости от используемого программного обеспечения терминала это можно сделать с помощью CTRL+D xили CTRL+Z на большинстве настольных платформ. Обратите внимание, что после закрытия может быть трудно снова открыть cin
.
Обычно я делаю что-то вроде варианта 2 в этом связанном ответе. Прочитайте всю строку из входного потока, запишите эту строку во второй поток. Прокрутите второй поток. В конце строки второй поток заканчивается, выходя из цикла.
@PaulMcKenzie: ты пропустил sort(words);
.
Альтернативой может быть труба: cat some_file | your_app
@ Jarod42 Да, я пропустил это. Тем не менее, использование std::set<std::string>
устранит необходимость в sort()
или последующем цикле for
.
Незначительная опасность: –
в words[i–1]
не является знаком минус.
cin >> temp не имел для меня смысла. Почему?
for(string temp; cin>>temp; ) // read whitespace-separated words
words.push_back(temp); // put into vector
Это эквивалентно:
string temp;
while (cin >> temp)
{
words.push_back(temp);
}
cin>>temp
будет оцениваться как false
, когда будет достигнут конец входного потока, и вызовет разрыв цикла. В противном случае temp
присваивается строка, а cin>>temp
оценивается как истина.
информация OP отсутствует: Что такое входной поток? Что им нужно для входа?
Если это перенаправленный файл из командной строки, то ничего. Если это из консоли, то я полагаю, что это CTRL+Z в Windows и CTRL+D в Unix/Mac.
Оператор >>
— это перегруженная функция.
Что на самом деле называется operator>>(cin, temp)
.
Функция возвращает сам поток (cin
), который имеет перегруженный оператор преобразования bool, который возвращает true
, если состояние потока в порядке. Он возвращает false
в случае ошибки, например, в конце файла.
Это означает, что поток и операторы ввода могут использоваться как часть логического условия для чтения до тех пор, пока вы не достигнете конца файла.
тот же комментарий здесь: отсутствует информация OP: что такое конец файла, когда они печатают на консоли? Что вводить?
@ 463035818_is_not_a_number: Этот пример скопирован (ничего не изменилось), и автор (изобретатель С++) попытался объяснить, что происходит после выполнения примера. В книге каким-то образом он был завершен, но когда я пробую тот же код, это не так.
cin >> temp
будет оцениваться как false
, если операция ввода завершится неудачно. Наиболее распространенная ошибка при чтении в string
— это достижение конца файла, и это условие, которое вы хотите вызвать.
В большинстве оболочек Linux (или других POSIX) маркер конца файла можно ввести, нажав ctrl+d
. В хосте консоли Windows это ctrl+x
.
В качестве альтернативы, вместо непосредственного взаимодействия с программой, вы можете связать ее ввод с выводом какой-либо другой команды с помощью конвейера. Когда команда, генерирующая вывод, завершается и закрывает свой конец канала, ваша программа увидит условие конца файла. Например, что-то вроде этого будет работать практически на любой оболочке:
echo "this is some text" | your-program
Или, используя большинство современных оболочек POSIX, вы можете использовать файл heredoc. Это работает в основном так же, как и выше, но сама оболочка записывает во входной поток вашей программы вместо того, чтобы подключать для этого внешнюю команду:
your-program <<EOF
this is some text
EOF
Я сохраню этот ответ, он может быть полезен в будущем. Спасибо.
Поскольку программа в настоящее время написана, поток не может быть прочитан, чтобы выйти из цикла. При чтении в std::string
это довольно сложно сделать, string
с радостью съест что угодно, не закрывая входной поток. В зависимости от используемого программного обеспечения терминала закрытие потока можно выполнить с помощью CTRL+D x или CTRL+Z на большинстве настольных платформ.
Обратите внимание, что после закрытия может быть трудно снова открыть cin
, поэтому обычно я делаю что-то вроде варианта 2 в этом связанном ответе. Прочитайте всю строку из входного потока, запишите эту строку во второй поток. Прокрутите второй поток. В конце строки второй поток заканчивается, выходя из цикла.
Тривиальная многострочная версия исходного кода может выглядеть так:
int main()
{
std::string line;
while (std::getline(cin, line))
{
std::istringstream iss(line); // #include <sstream>
vector<string> words;
for(string temp; iss>>temp; ) // read whitespace-separated words
words.push_back(temp); // put into vector
cout << "Number of words: " << words.size() << '\n';
sort(words); // sort the words
for (int i = 0; i<words.size(); ++i)
if (i==0 || words[i-1]!=words[i]) // is this a new word?
cout << words[i] << "\n";
}
}
Это сработало, хотя использовались некоторые дополнительные темы, такие как потоки строк, но я понял, что пример, упомянутый в книге на данный момент, не может завершить строку без дополнительной помощи, такой как код, который вы упомянули.
Не по теме, но --
if (i==0 || words[i–1]!=words[i])
не будет работать для чего-то вродеapple banana apple banana
. Самое простое решение — использоватьstd::set<std::string>
, так как он не только сортирует, но и хранит только уникальные элементы.