-1

I just started learning C++ after previously coding with Java. The code below takes input from the user and validates the input. The first piece asks for the number of voters, which must be a positive number. If I enter a negative number the program behaves as I expected. It prints out the error message and asks for the input again. However, if I enter any other character, such as any alphabet letter I get an infinite loop in the console, asking for input and printing the error message. What am I doing wrong?

my code:

#include <iostream>
using namespace std;

struct dataT {
    int numOfVoters = -1;
    float preSpread = -1;
    float votingError = -1;
};

void getUserInfo() {
    dataT data;
    while (data.numOfVoters == -1) {
        cout << "enter the number of voters" << endl;
        cin >> data.numOfVoters;
        if (data.numOfVoters <= 0) {
            data.numOfVoters = -1;
            cout << "Invalid entry, please enter a number larger than zero." << endl;
        }
    }
    while (data.votingError == -1) {
        cout << "enter the percentage spread between candidates" << endl;
        cin >> data.votingError;
        if (data.votingError <= 0 || data.votingError >= 1) {
            data.votingError = -1;
            cout << "Invalid entry. Enter a number between 0 to 1." << endl;
        }
    }
    while (data.preSpread == -1) {
        cout << "Enter the precentage spread between the two candidates." << endl;
        cin >> data.preSpread;
        if (data.preSpread <= 0 || data.preSpread >= 1) {
            data.preSpread = -1;
            cout << "Invalid input. Enter a number between 0 and 1." << endl;
        }
    }
}

int main() {
    getUserInfo();
    return 0;
}

Console:

enter the number of voters
f
Invalid entry, please enter a number larger than zero.
enter the number of voters
Invalid entry, please enter a number larger than zero.
enter the number of voters
Invalid entry, please enter a number larger than zero.
...
...
...
user2573222
  • 207
  • 4
  • 15
  • 6
    Your input failed. You never checked for input failing, just having an invalid value that you assume is meaningful after a failed input. – chris Oct 10 '14 at 16:27
  • Related: http://stackoverflow.com/questions/24504582/test-whether-stringstream-operator-has-parsed-a-bad-type?noredirect=1#comment37965807_24504582 – πάντα ῥεῖ Oct 10 '14 at 16:29
  • in the first "WHILE" loop, u only check for negative number, and as long as it is not negative, you code will accept it, make sure do a cast to int – Luo Sen Oct 10 '14 at 16:30
  • @chris, sorry for the novice question, but can you elaborate a bit on how I should check for input failing? – user2573222 Oct 10 '14 at 16:35
  • No need. There's a [FAQ entry](http://isocpp.org/wiki/faq/input-output#stream-input-failure). – chris Oct 10 '14 at 16:37
  • @chris, thanks! For future reference, can anyone explain why this question was down voted? – user2573222 Oct 10 '14 at 16:40

3 Answers3

2

If you write cin >> integervariable but in cin there are character that cannot represent an integer, the input fails, !cin becomes true, and the character remain there until you don't reset the input state from the error and consume the wrong characters.

a proper check can be

while(integervariable has not good value)
{
    cout << "prompt the user: ";
    cin >> integervariable;
    if(!cin) //something wrong in the input format
    { 
       cin.clear(); //clear the error flag
       cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discard the rubbish
       cout << "prompt error message \n";
    }
}
Emilio Garavaglia
  • 20,229
  • 2
  • 46
  • 63
0

Your if statements are always true, you want something more like:

if (data.votingError < 0 || data.votingError > 1) {
    ...

then data.votingError can take on a value different from -1 and exit your loop.

Paul Evans
  • 27,315
  • 3
  • 37
  • 54
0

The std::cin object will check whether or not it is in a valid state every time it reads. If you enter a char where your program expects an int, then you'll "break" the input stream. All subsequent calls to std::cin will then be effectively skipped until you manually reset the input stream. When this happens, you'll never be able to set your values to anything other than -1, and your if statement always evaluates to true, causing an infinite loop.

As an aside, you can check for failure state by including && cin in all of your tests. Input objects implicitly evaluate to true if the stream is in a valid state and to false if the stream is in a failure state instead.

FBeckwith
  • 1
  • 3