0

I am reading "C++ primer plus/Stephen Prata"

Here is the code from this book

    while (!(cin >> golf[i])) {
        cin.clear();    // reset input
        while (cin.get() != '\n')
            continue;   // get rid of bad input
        cout << "Please enter a number: ";
    }

The code above is easy to understand.

But the context from this book mentions

"...the program uses cin.get() in a while loop to read the remaining input through the end of the line.This gets rid of the bad input, along with anything else on the line. Another approach is to read to the next whitespace, which gets rid of bad input one word at a time instead of one line at a time. Finally, the program tells the user to enter a number."

I wonder what the another approach is?

I try to express the code in different way and I know it's not correct.

    while (!(cin >> golf[i])) {
        cin.clear();    // resset input
        char word[20];
        while (cin >> word)
            continue;   // get rid of bad input
        cout << "Please enter a number: ";
    }

How do I code to read to the next whitespace, which gets rid of bad input one word at a time instead of one line at a time?

thank you for your reading.

Stats Cruncher
  • 155
  • 1
  • 1
  • 6
  • 3
    You might want to edit the title of your question so that it makes sense without the context of the quote. – SirDarius Feb 20 '15 at 14:41
  • 4
    You might also want to take a look at [The Definitive C++ Book Guide and List](http://stackoverflow.com/a/388282/1171191), which avoids recommending this book (and looking at the code sample, I can see why!), linking to an unfavourable review. It suggests several other beginner books that may be preferable. – BoBTFish Feb 20 '15 at 14:45
  • 1
    Thanks. Is the new title okay? – Stats Cruncher Feb 20 '15 at 14:55

2 Answers2

3

Let's start by looking at the existing code:

    while (cin.get() != '\n')
        continue;

This is what reads up to the new-line. We read a character, compare it to the new-line, and if it's not equal, we read another character. So, it reads characters, and stops reading when it gets to a new-line.

If we want to read to a space character instead, we just change the value we compare to:

    while (cin.get() != ' ')
        continue;

If we want to stop reading at any white-space, we could use a function to tell us whether a character is white space or not. That function would look something like this:

bool is_white_space(char ch) { 
    return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\v';
}

But this is a common enough task that the standard library already has an isspace function, so we don't have to write our own. We just have to use it:

while (!isspace(cin.get())
    continue;

Personally, I'd at least consider putting this into a function by itself, and giving it a readable name like skip_to_whitespace, so our outer loop would look something like:

void skip_to_space(std::istream &in) { 
    in.clear();
    while (!isspace(in.get()))
        continue;
}

// ...
while (!(cin >> golf[i])) {
    skip_to_space(cin);
    cout << "Please enter a number: ";
}

At least to me, this seems to make the intent of the code considerably more apparent--we don't have to read through the content of the loop to figure out what it's supposed to do--that's obvious from the name of the function.

There is one last thing I'd change though. A while loop should normally have no effect if its condition is false. This one, however, always reads at least one character from its input, regardless of what that character might be. To make that fact more apparent, I'd prefer to use a do loop, to correctly reflect the intent that the loop always executes at least once:

void skip_to_space(std::istream &in) { 
    in.clear();
    char ch;

    do {
        ch = in.get();
    } while (!isspace(ch));
}

Now it's obvious that the cin.get() always happens at least once, and continues to happen until we reach a white-space character.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
0

To throw out words until you reach a number do this:

string word;

cout << "Please enter a number: ";

while(!(cin >> golf[i])){
    cin.clear();
    cin >> word;

    if(cin.rdbuf()->in_avail() == 1){
        cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        cout << "Please enter a number: ";
    }
}

One method of throwing out an entire line would be to use ignore.

while (!(cin >> golf[i])) {
    cin.clear();    // resset input
    cin.ignore(numeric_limits<streamsize>::max(), '\n');   // get rid of bad input
    cout << "Please enter a number: ";
}
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288