Каковы правила объекта std::cin в C++?
Вопрос
Я пишу небольшую программу для личного использования, чтобы попрактиковаться в изучении C++ и для ее функциональности, генератор цитирования MLA (я пишу большую статью с десятками цитат).
Из-за отсутствия лучшего способа сделать это (я не понимаю классов или использования других файлов .cpp внутри вашего основного файла, так что не беспокойтесь, я поработаю над этим, когда у меня будет больше времени), я пишу функция для каждого типа цитирования.Я мог бы разбить это на функцию для каждого повторно используемого кода, если у меня будет больше времени.
Мой вопрос:как работает объект std::cin?В настоящее время я читаю std::cin >> для строк, которые, как я ожидаю, будут отдельными словами, и getline(std::cin, string) для строк с пробелами.Однако я не получаю правильный результат.Я просто хочу знать, как работает std::cin и почему я продолжаю неожиданно пропускать некоторые входные данные (например, он пропускает веб-страницу вместо того, чтобы дать мне возможность ввести в нее данные).
void webCit()
{
std::cout << "Leave any unknowns blank.\n";
std::cout << "Author last name: ";
std::string lastName;
std::cin >> lastName;
if (lastName.size() != 0)
{
lastName = lastName + ", ";
}
std::cout << "Author first name: ";
std::string firstName;
std::cin >> firstName;
if (firstName.size() != 0)
{
firstName = firstName + ". ";
}
std::cout << "Article title: ";
std::string articleTitle;
getline(std::cin, articleTitle);
if (articleTitle.size() != 0)
{
articleTitle = "\"" + articleTitle + ".\" ";
}
std::cout << "Title of web page: ";
std::string pageTitle;
std::cin >> pageTitle;
if(pageTitle.size() != 0)
{
pageTitle = pageTitle + ". ";
}
std::cout << "Publication date: ";
std::string publicationDate;
getline(std::cin, publicationDate);
if(publicationDate.size() != 0)
{
publicationDate = publicationDate + ". ";
}
std::cout << "Web address: ";
std::string webAddress;
getline(std::cin, webAddress);
webAddress = "<" + webAddress + ">. ";
std::cout << "Date accessed: ";
std::string dateAccessed;
getline(std::cin, dateAccessed);
if(dateAccessed.size() != 0)
{
dateAccessed = dateAccessed + ". ";
}
std::string citation =
lastName + firstName + articleTitle + pageTitle + publicationDate + webAddress + dateAccessed;
std::cout << citation; //TEST; remove after
}
РЕДАКТИРОВАТЬ:ввод/вывод
Leave any unknowns blank.
Author last name: Hooked
Author first name: Jerbear
Article title: Title of web page: title
Publication date: Web address: www.win.com
Date accessed: 4/29/09
Hooked, Jerbear. Title. <www.win.com>. 4/29/09.
Как видите, что-то идет не так, потому что мой ввод пропускается.
Решение
Здесь происходит то, что std::cin >> firstName;
читает только до но не включая первый символ пробела, который включает в себя новую строку (или '\n'
), когда вы нажимаете Enter, поэтому, когда он дойдет до getline(std::cin, articleTitle);
, '\n'
по-прежнему следующий персонаж в std::cin
, и getline()
возвращается немедленно.
// cin = "Bloggs\nJoe\nMan of Steel, Woman of Kleenex\n"
std::cin >> lastName;
std::cin >> firstName;
// firstName = "Joe", lastName = "Bloggs", cin = "\nMan of Steel, Woman of Kleenex\n"
getline(std::cin, articleTitle);
// articleTitle = "", cin = "Man of Steel, Woman of Kleenex\n"
Добавление 'std::cin >> std::ws
' (ws
значение w
ударитьs
темп), прежде чем ваши вызовы getline() устранят проблему:
std::cin >> firstName >> std::ws;
getline(std::cin, articleTitle);
Но будет легче увидеть, где вы это пропустили, если вы сделаете это в аргументе:
std::cin >> firstName;
getline(std::cin >> std::ws, articleTitle);
Другие советы
Когда вы используете >>
оператор, cin
считывает до следующего символа пробела, но не обрабатывает пробел.Итак, когда у вас есть
std::cin >> str1;
std::getline(std::cin, str2);
второй вызов будет просто обрабатывать символ новой строки, и у вас не будет возможности ввести какой-либо ввод.
Вместо этого, если вы планируете использовать getline
после operator >>
, вы можете позвонить std::cin.ignore()
съесть новую строку перед вызовом getline
.
Редактировать:это работает так, как вы ожидали, когда вы это делаете
std::cin >> str1;
std::cin >> str2;
поскольку второй вызов будет игнорировать все начальные пробелы.