c++iostreamcingetline

What are the rules of the std::cin object in C++?


I am writing a small program for my personal use to practice learning C++ and for its functionality, an MLA citation generator (I'm writing a large paper with tens of citations).

For lack of a better way to do it (I don't understand classes or using other .cpp files inside your main, so don't bother telling me, I'll work on that when I have more time), I am writing a function for each type of citation. I might break this down into a function for each reused code if I get more time.

My question is: How does the std::cin object work? I am currently reading in with std::cin >> for the strings I expect to be single words and getline(std::cin, string) for the strings with spaces. I am not getting the right output, though. I just want to know how std::cin works and why I keep unexpectedly skipping over some inputs (for instance, it skips over webPage instead of giving me a chance to input into it).

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: Doe
Author first name: John
Article title: Title of web page: title
Publication date: Web address: www.win.com
Date accessed: 4/29/09
Doe, John. Title. <www.win.com>. 4/29/09. 

As you can see, something is going wrong, because my input is getting skipped over.


Solution

  • What is happening here is that std::cin >> firstName; only reads up to but not including the first whitespace character, which includes the newline (or '\n') when you press enter, so when it gets to getline(std::cin, articleTitle);, '\n' is still the next character in std::cin, and getline() returns immediately.

    // 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"
    

    Adding 'std::cin >> std::ws' (ws meaning whitespace) before your calls to getline() fixes the problem:

    std::cin >> firstName >> std::ws;
    getline(std::cin, articleTitle);
    

    But it is easier to see where you missed it if you do it in the argument:

    std::cin >> firstName;
    getline(std::cin >> std::ws, articleTitle);