开发者

cin.getline not executing c++

For some weird reason my input line cin.getline(oneLine, 80); is completely ignored when I put it in this else if block. I can't understand why be开发者_JAVA技巧cause when I move it somewhere else in the program, it works.

     else if (choice == "user-id")
     {   
        cout << endl << "Enter a full name e.g. John Smith ";
        char oneLine[80];
        cin.getline(oneLine, 80);
        cout << oneLine;                        
     }

Here's the rest of my code. I'm new to C++ so I'm sure a lot of my conventions may be questionable at best.

int main( )
{
    while (true)
        {

        int pause;
        string choice = "proceed";
        string nameGiven;
        string userIdGiven;
        string result;
        using namespace std ;

        while ((choice != "name") && (choice != "user-id"))
        {   
            cout << "Would you like to search for a name or user-id? ";
            cin >> choice;
            if ((choice != "name") && (choice != "user-id"))
               cout <<"Please enter a valid choice (name or user-id)" << endl;
        }

        if (choice == "name") 
        {
            string dataType = "int";
            while (true)
            {    
                cout << endl << "Enter a valid user id (4 digit maximum) ";
                cin >> userIdGiven;

                if (valid(userIdGiven))
                   break;
                else
                    cout << endl << "Not a valid number. " << endl;
                   continue;
             }
             result = findData(userIdGiven, dataType);
             cout << "name: " << result;

         }

         else if (choice == "user-id")
         {   
            cout << endl << "Enter a full name e.g. John Smith ";
            char oneLine[80];
            std::getline(oneLine, 80);
            cout << oneLine;                       
         }

        string ans;
        cout << endl << "Would you like to play again? (yes/no) " << endl;
        cin >> ans;
        if ( (ans == "yes") || (ans == "Yes") || (ans == "Y") || (ans == "y") )
             continue;
          else
              break;

        cin >> pause;
     } 
return 0;
}


Your std::cin object is in a bad state (std::cin.good() == false) from a previous input operation. For example, you might have tried to read a number, but there were only nun-numeric characters in the input buffer.

Always check for input success before continuing using a std::istream.

Note: Don't use the old input functions operating with char*, as they are more complicated and less safe to use than the new ones operating on std::string. In your case, use std::getline(std::istream&, std::string&, char = '\n').


twsaef's comment's substantively correct... you're streaming a string into choice, which consumes the characters up until but excluding the next whitespace character - you're probably typing a newline to terminate your input, so it's left in the buffer. Then you use getline which sees that newline and reads an empty string.

Easiest solution is to call getline() to read the initial string too, then check if choice is "name\n" or "user-id\n". Better - write a "trim" function to remove the whitespace from the line before comparison (boost string library has this already). Otherwise, you could use read and ignore characters from std::cin until you get a '\n'. Or even read a line then put in into a stringstream and read a string from there.... Lots of choices.

And, please check your stream state! Try to use:

if (std::cin >> x)
    // x was parsed from stream... use it
else
    // print an error so you know where things failed!


FWIW, I guessed what the problem would be (it's stupidly common) before seeing the update, and chuckled to myself at the other guesses (although they make very good points even if they missed the OP's problem).

The line of code is working correctly and as advertised. It doesn't happen to be working the way you want it to.

When you read from std::cin, that does not pause the program and wait for input. What causes the pause is the lack of sufficient input data for the read operation.

Input is fed to your program a line at a time. Remember, the console window is a program, too. It is responsible for translating the user's key-presses into text characters (bytes, really), handling things like the backspace key, and gathering it all up into lines.

So say you read an int with operator>>, and then read a line with getline. The program will not see an int until the user hits the Return key, because that triggers the console to feed a line of input to your program.

operator>> will skip leading whitespace, read the integer, and leave trailing whitespace alone. Newline characters are whitespace. There is a newline character in the input (at the end of the line, obviously).

getline() will not skip any leading whitespace, and read until the next newline. The very next character happens to be a newline, so getline() happily reads an empty line and the program proceeds with that.

So how do you fix that? Chances are, if you're reading all your input from cin, that you want the program to pause every time you come to a reading operation. The way to do that is to ensure that there is never any available data at that point, and the way to do that is to read everything that's available - i.e., the whole line - every time that you read something.

So, always read a full line from cin. As noted by wilx, please use the free function std::getline for this. Do not use the .getline member function of the stream. Use std::string to represent strings of text. That's what it's there for. It will make your life much, much easier. That also means that if you're expecting an integer and the user types "76 trombones", you get rid of the "trombones" data (and can decide whether you want to just throw it away, or yell at the user and make him re-enter a number without any funny commentary).

But then what? You just have a string, where you may have wanted an int. Fortunately, there is a simple solution for that. We can treat the string as a source of stream data, using the standard library class std::stringstream. We just construct a stringstream from the string, and then use it just like std::cin - i.e. we can read from it with operator>>, check the stream state to see if reading was successful, etc.

As noted by sbi, always check whether reading succeeded! If you try to read an int and the stream contains text like "hi mom", then (a) the int variable will not be altered (so if it was uninitialized it is still uninitialized, a very dangerous state to be in), and (b) the stream will go into a "failed" state and will not read any more until you clear it, and (c) even if you clear it, the data will still be there, which can trigger an infinite loop if you're not careful.

Fortunately, with the separate stringstream, we avoid all kinds of complications. If reading fails, then all those things happen to the stringstream object - not to std::cin. The getline operation will always succeed on std::cin unless perhaps the user explicitly indicates an end-of-file (control-D character on Linux, or control-Z on Windows). We can easily check if the stringstream is in the failed state, loop and just create another one - the old one will automatically get cleaned up.

We can even make a helper function like:

template <typename T>
// Attempt to read into to_read, and return whether successful.
bool read_primitive_from_input(std::istream& input, T& to_read) {
    std::string line;
    std::getline(std::cin, line);
    std::istringstream iss(line);
    return iss >> to_read;
}

std::stringstream is provided by the standard library header <sstream>. std::string comes from <string>, of course.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜