2009-04-30 8 views
0

Я пишу небольшую программу для моего личного использования, чтобы практиковать изучение C++ и его функциональность, генератор цитат MLA (я пишу большую газету с десятками цитат).Каковы правила объекта std :: cin в C++?

Из-за отсутствия лучшего способа сделать это (я не понимаю классы или другие файлы .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 
} 

EDIT: I/O

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. 

Как вы можете видеть, что-то происходит не так, потому что мой вход становится пропускаются.

+0

Я не вижу очевидных проблем с тем, как вы это делаете ... Можете ли вы скопировать и вставить свое взаимодействие с помощью t его программу, точные входы и выходы, которые у вас есть? Кроме того, я бы рекомендовал поставить «using namespace std;» наверху (обычно сразу после всех ваших # include), чтобы вы могли просто сказать «cin» и «cout», не записывая std :: снова и снова. Но вам, конечно, не обязательно ... в любом случае. – MatrixFrog

+0

Я добавил несколько ввода-вывода. – jkeys

+0

@MatrixFrog: Я предпочитаю использовать 'std :: cin; используя std :: cout; ... 'или помещать' using namespace std; 'внутри функций, которые его используют, а не на глобальном уровне. –

ответ

6

Что происходит здесь в том, что std::cin >> firstName; читает только до но не включая первый символ пробела, который включает в себя символ новой строки (или '\n') при нажатии клавиши ввода, поэтому, когда он попадает в 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); 
+0

Я как раз собирался добавить ws тоже: P – sfossen

+0

Это * не * что происходит для нескольких cin >> s! –

+0

@Jesse: О, я понимаю, что вы имеете в виду «несколько cin >> s». Похоже, он ведет себя одинаково. –

2

При использовании оператора >>cin считывает до следующего символа пробела, но не обрабатывает пробелы. Поэтому, когда у вас есть

std::cin >> str1; 
std::getline(std::cin, str2); 

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

Вместо этого, если вы планируете использовать getline после operator >>, вы можете позвонить std::cin.ignore(), чтобы съесть новую строку, прежде чем позвонить по телефону getline.

Edit: он работает, как вы ожидали, когда вы делаете

std::cin >> str1; 
std::cin >> str2; 

со второго вызова будет игнорировать все ведущие пробелы.

+1

также обратите внимание, что оператор >> и getline возвращают логическое значение, которое истинно, когда оно успешно считывает входное значение, false, если произошла ошибка, конец файла или сбой форматирования. – Aaron

+1

@Aaron: если быть точным, они возвращают istream, который можно преобразовать в void *, который можно преобразовать в bool (whew!), Который является значением! Is.fail(). Вот почему работает 'std :: cin >> lastName >> firstName;'. –