Thread: Simple question with the getline() function.

  1. #1
    Devil's Advocate SlyMaelstrom's Avatar
    Join Date
    May 2004
    Location
    Out of scope
    Posts
    4,079

    Simple question with the getline() function.

    Is there a proper way to dump the newline character from the input stream so you can use the getline() function without it screwing up?

    For instance:

    Code:
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int main() {
        int number;
        string textLine;
        
        cout << "Input a number: ";
        cin >> number;              // Takes the number, leaves the \n
        cout << "Enter a string:" << endl;
        getline(cin, textLine);
        
        cout << "You wrote the number " << number << " and the line:" << endl
             << textLine;
        
        cin.get();
        
        return 0;
    }
    This doesn't work properly cause getline() will see the \n left by the last input and accepts the string as nothing.

    What I usually end up doing is this:

    Code:
    // CODE HERE
    
        char dumpNL;   // To dump the \n
        
        cout << "Input a number: ";
        cin >> number;              
        cin.get(dumpNL);        // Clears the \n
    
    // CODE HERE
    Is there a more proper way to dump the newline character from the stream?
    Last edited by SlyMaelstrom; 10-13-2005 at 09:03 AM.
    Sent from my iPadŽ

  2. #2
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    If a newline is sure to be the next character, you can do this:
    Code:
    cin.ignore();
    But a more general solution discards unread characters from the stream:
    Code:
    #include <limits>
    
    cin.ignore ( numeric_limits<streamsize>::max(), '\n' );
    My best code is written with the delete key.

  3. #3
    Devil's Advocate SlyMaelstrom's Avatar
    Join Date
    May 2004
    Location
    Out of scope
    Posts
    4,079
    Thank you, very much.

    That limits fuction seems useful, but I doubt I'll be programming anything, yet, that would need more than cin.ignore(50, '\n') to clear the stream.
    Sent from my iPadŽ

  4. #4
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >I doubt I'll be programming anything, yet, that would need more than cin.ignore(50, '\n') to clear the stream.
    You should still avoid magic numbers. 50 is way too arbitrary for my tastes, but you might be able to live with it.
    My best code is written with the delete key.

  5. #5
    Registered User
    Join Date
    Mar 2002
    Posts
    1,595
    Since my programming is for my own pleasure, and not for sale/public consumption, I don't generally try to bullet proof my code. However, I wonder if there needs to be an even more general solution to this problem. The situation I'm thinking of is below:
    Code:
    int ID;
    char name[256];
    cout << "enter an integer ID" << endl;
    cin >> ID;
    cout << "enter full name in following fashion : last, first, middle initial " << endl;
    cin.getline(name, 255);
    
    and the input is:
    3157 <enter> <enter>
    Doe, Jane, S. <enter>
    In the above snippet, the user inadvertantly hit the enter (new line) key twice instead of once. Thus, if the line:

    cin.ignore(numeric_limits<streamsize>::max(), '\n');

    syntax were inserting per "routine", it would successfully ignore the first newline after the ID was entered, but not the second.

    Admittedly, most users aren't going to hit the enter key more than once in succession very often, but it certainly isn't outside the realm of improbability either. If the intention was to fool proof the code as much as possible, how would you handle ignoring multiple newlines in this situation?
    You're only born perfect.

  6. #6
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> how would you handle ignoring multiple newlines in this situation?

    Check the result of the getline to see if it was empty and re-prompt or just call getline again until it gets actual data.

  7. #7
    Registered User Tonto's Avatar
    Join Date
    Jun 2005
    Location
    New York
    Posts
    1,465
    Problem: The getline template function reads an extra character after encountering the delimiter
    The Fix: http://support.microsoft.com/default...b;en-us;240015

    I believe that is your issue here. Edit: Daved's right, definitely not the problem. Just a bad quick glance.
    Last edited by Tonto; 10-13-2005 at 01:47 PM.

  8. #8
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Actually, Tonto, I don't think that's the issue with SlyMaelstrom or elad's question.

  9. #9
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >In the above snippet, the user inadvertantly hit the enter (new line) key twice instead of once.
    ID will have the value 3157 and name will contain an empty string. How do you propose a general solution that disallows what could be perfectly normal behavior? If empty strings aren't allowed then you can test for that, but if they are allowed, there's a certain amount of trust that you have to give to the end user. And by trust I mean show them what they entered and give them the option of verifying that it was correct. You see that a lot with the "Are you sure?" prompts.
    My best code is written with the delete key.

  10. #10
    Registered User jlou's Avatar
    Join Date
    Jul 2003
    Posts
    1,090
    I find the following general solution to be an easy way to get console input without a lot of the hassles that newbies normally trip over.

    template<typename T>
    bool simple_input(std::istream& is, T& x, char delim = '\n');

    template<typename T>
    bool simple_checked_input(std::istream& is, T& x, char delim = '\n');

    The idea is that after each call, cin will be left in a good state and with no leftover characters in the stream. Numbers, characters, and strings can all be read in the same way with this function. Here is an example usage:
    Code:
    #include <iostream>
    #include <string>
    #include "simple_input.h"
    
    int main()
    {
        using namespace std;
        using namespace jlou;
    
        string s;
        cout << "Enter a line of text: ";
        simple_input(cin, s);
        cout << "The line of text read in was: " << s << endl;
    
        int i;
        cout << "Enter an int: ";
        if (simple_input(cin, i))
            cout << "The number read in was: " << i << endl;
        else
            cout << "Sorry, invalid int!" << endl;
    
        double d;
        cout << "Enter a double: ";
        while (!simple_input(cin, d))
        {
            cout << "Invalid double! Try again: ";
        }
        cout << "The double read in was: " << d << endl;
    }
    And here is the basic implementation. I've attached a file that can be included and used as is, and contains special code for VC++ 6.0 if that is your compiler.
    Code:
    #include <istream>
    #include <ios>
    #include <string>
    #include <limits>
    
    namespace jlou
    {
        template<typename T>
        inline bool simple_input(std::istream& is, T& x, char delim = '\n')
        {
            if (is >> std::noskipws >> x >> std::skipws && (is.eof() || is.get() == delim))
                return true;
    
            x = T();
            is.clear();
            is.ignore(std::numeric_limits<std::streamsize>::max(), delim);
            return false;
        }
    
        template<>
        inline bool simple_input<std::string>(std::istream& is, std::string& x, char delim)
        {
            if (std::getline(is, x, delim))
                return true;
            x.clear();
            is.clear();
            return false;
        }
    
        template<typename T>
        inline void simple_checked_input(std::istream& is, T& x, char delim = '\n')
        {
            if (!simple_input(is, x, delim))
                throw std::ios_base::failure("input format not valid");
        }
    }
    I posted this before on this site a while ago, but I've updated it since with input from other forums.

  11. #11
    Registered User
    Join Date
    Mar 2002
    Posts
    1,595
    Thank you, all.

    EDIT: I was hoping maybe you could just ignore up to streamsize number of char irrespective of the type of char or until input buffer was empty (without the need for a terminating char), but I guess not.
    Last edited by elad; 10-13-2005 at 03:23 PM.
    You're only born perfect.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Function name basic question help
    By kenryuakuma in forum C++ Programming
    Replies: 7
    Last Post: 09-24-2008, 07:48 AM
  2. A simple question of a C++ function
    By meili100 in forum C++ Programming
    Replies: 3
    Last Post: 05-07-2007, 06:49 PM
  3. Question on function syntax and calling function
    By cbrman in forum C Programming
    Replies: 10
    Last Post: 10-05-2003, 05:32 PM
  4. Replies: 5
    Last Post: 02-08-2003, 07:42 PM
  5. I need help with passing pointers in function calls
    By vien_mti in forum C Programming
    Replies: 3
    Last Post: 04-24-2002, 10:00 AM