4

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?

Kevin Panko
  • 8,356
  • 19
  • 50
  • 61
  • 3
    You should really not write that kind of code, it's very hard to understand what happens and where the error is. – Djon May 29 '13 at 14:37
  • 1
    Hint: http://en.cppreference.com/w/cpp/io/basic_istream/ignore – aschepler May 29 '13 at 14:38
  • @Djon I find the code quite clear and the error is easy to spot. What exactly bothers you about it? – jrok May 29 '13 at 14:49
  • 2
    I have never seen cin and cout in a while before and I find it very confusing, but I admi that people may find it quite clear. However, given the question, OP seems to be new and this might not be the best way to learn as everything is packed up on one line. – Djon May 29 '13 at 14:51

3 Answers3

5

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.

Captain Obvlious
  • 19,754
  • 5
  • 44
  • 74
  • it does not work if i give '233dsjfeu4' as input as it reads it as 233 and then giver the error, but works fine with '342365465235436436' or 'ddsfdfdggv' – Amolak Chandel May 30 '13 at 01:59
  • @AmolakChandel i've updated my answer to include validation that ensures only a number is entered. Any trailing characters except whitespaces will indicate failure. – Captain Obvlious May 30 '13 at 04:50
2

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'); 
Community
  • 1
  • 1
Déjà vu
  • 28,223
  • 6
  • 72
  • 100
  • @jrok I don't like the default (1, EOF). And giving a concrete example (100) for a beginner is more explicit than `std::numeric_limits::max()` for instance. Indeed, I should have added a link to the doc (done). – Déjà vu May 29 '13 at 15:03
  • 1
    And what happens if the user enters more than 100 characters? – Captain Obvlious May 29 '13 at 15:06
-1

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.

m01
  • 9,033
  • 6
  • 32
  • 58