Amolak Chandel
Amolak Chandel

Reputation: 55

stuck in infinite while loop

In C++, for handling wrong inputs (like when the program asks for an integer but you type a character) it should be able to do something and then loop to repeat the input.

My loop iterates infinitely when you input a character when an integer is needed and vice versa:

#include<iostream>

int main()
{
    while (cout << "Enter a number" && !(cin >> num)) 
    {
        cin.sync(); 
        cin.clear();
        cout << "Invalid input; please re-enter.\n";
    }
}

What should I do so that the program prompts for the new input again?

Upvotes: 4

Views: 1245

Answers (3)

Captain Obvlious
Captain Obvlious

Reputation: 20073

If cin >> num fails the invalid input needs to be removed from the stream. I suggest using ignore instead of sync to accomplish this. The reason is sync is not guaranteed to remove the remaining input in all implementations of the Standard Library.

#include <iostream>
#include <limits>

int main()
{
    int num;
    while (cout << "Enter a number" && !(cin >> num)) 
    {
        cin.clear();    // clear the error

        // Remove input up to a new line
        cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
        cout << "Invalid input; please re-enter.\n";
    }
}

The above example uses std::numeric_limits<std::streamsize>::max() is used to retrieve the maximum number of characters the input buffer can hold. This allows ignore() to remove as many characters as possible up to the new line. It is idiomatic C++ and is preferred over using magic numbers which are likely to just hide the problem you are currently having.

This works well but does not handle situations where the input contains extra characters after the number. To deal with those situations the loop needs to be changed a bit to handle the additional validation. One option is to read an entire line from cin, place it into a std::stringstream, read the number from that and then do additional validation. There is one special case that might need to be taken into account though - a line where the only characters after the number are whitespaces. Luckily the Standard Library provides the stream modifier std::skipws that allows the situation to be handled easily. The example below shows how to do this without much effor

#include <iostream>
#include <sstream>

int main()
{
    int num;

    for(;;)
    {
        std::cout << "Enter a number: " << std::flush;

        std::string line;
        std::getline(std::cin, line); // Read a line from console
        std::stringstream text(line); // store in a string stream

        char ch = 0;
        if(!(text >> num).fail() && (text >> std::skipws >> ch).fail())
        {
            break;
        }

        std::cout << "Invalid input; please re-enter.\n";
    }

    return 0;
}

The expression (text >> std::skipws >> ch).fail() will skip all white spaces that appear after the number and then attempts to read a single character. If no character is available the read will fail indicating the user entered only a number and nothing else. If we tried to do this with cin it would wait for the user to enter more text even if the input is valid.

Upvotes: 5

D&#233;j&#224; vu
D&#233;j&#224; vu

Reputation: 28850

Use cin.ignore() instead of cin.sync() and see why from this answer

while (cout << "Enter a number" && !(cin >> num)) {
    cin.clear();           // clear error
    cin.ignore(100, '\n'); // ignore characters until next '\n' (or at most 100 chars)
    cout << "Invalid input; please re-enter.\n";
}

More on cin.ignore

Note that you can extend the scope of the number of ignored characters, up to the maximum

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

Upvotes: 2

m01
m01

Reputation: 9395

You could just read the input as a string, convert it to an integer and validate it..

#include <iostream>
#include <string>
using namespace std;
int main()
{
    int number = 0;
    string input;
    do {
        cout << "Enter a number: ";
        cin >> input;
        number = atoi(input.c_str()); // atoi returns 0 on error..
        if (number != 0 || input.compare("0") == 0) // but maybe the user really entered "0".
            break;
        cout << endl;
        cout << "Invalid input; please re-enter.\n";
    } while (1);
    cout << "You entered " << number << endl;
    return 0;
}

Sample program execution:

% ./foo
Enter a number: abc

Invalid input; please re-enter.
Enter a number: 2
You entered 2
% ./foo
Enter a number: 0
You entered 0

.. though this probably isn't the most elegant solution.

Upvotes: -1

Related Questions