Trying to Track an Infinite Loop (Input Validation)

I had a working error validation check in my first program, it went like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void gpa()
{
    //Variable declaration
    char grade; //Stores inputted grade.
    char gradePlus; //Stores whether grade is +/-
    char confirm; //Y/N choice for running confirmation loop.
    int hours = 0; //Stores course hours for each class.
    int numClasses = 0; //Controls loop for total classes to calculate.
    double totalHours = 0; //Sum total of course hours for calculating GPA.
    double gradePoints = 0; //Sum total quality points based on letter conversion.
    double gpa = 0; //Stores calculated GPA.

    //Prompts user to enter the total number of classes for the given term.
    //Provides clear instructions not to include pass/fail classes.
    cout << "How many classes would you like to calculate for this term? " << endl;
    cout << "Do not include PASS/FAIL classes, as these do not affect GPA: ";
    cin >> numClasses; //Stores number of classes for loop and later math.
    cin.ignore (100, '\n');

    while (!cin >> numClasses) //WHILE LOOP FOR ERROR DETECTION
    {
        cin.clear();
        cout << "\nInvalid choice, please try again: ";
        cin >> numClasses;
        cin.ignore(100, '\n');
    }


However, when I put it in my new code, for some reason it gives an infinite loop. Here is the new code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//Start of main function.
int main ()
{

    int choice = 0; //Integer variable for menu choice.
    bool exit = false; //Boolean value for menu exit condition.
    char phraseOne[SIZE] = {0}; //Character array for phrase stored in pos 1.
    char phraseTwo[SIZE] = {0}; //Character array for phrase stored in pos 2.
    char phraseThree[SIZE] = {0}; //Character array for phrase stored in pos 3.
    char phraseFour[SIZE] = {0}; //Character array for phrase stored in pos 2.
    char signature[SIZE] = {0}; //Character array for signature entry.
    char signatureNew[SIZE] = {0}; //Character array for signature edited.

    welcome(); //Call to welcome function, displaying program welcome.

    do { //Begin Do Loop for Main Menu Switch
    menu(); //Call to menu function, displaying the main menu.
    cin >> choice; //Store menu choice in choice integer.
    cin.ignore (100, '\n'); //Clear input.

    while (!cin >> choice) //WHILE LOOP FOR ERROR DETECTION
    {
        cin.clear();
        cout << "\nInvalid choice, please try again: ";
        cin >> choice;
        cin.ignore(100, '\n');
    }

    switch (choice) //Initiate switch based on choice.
    {
        case 1: //Calls to phrase submenu.
            phraseMenu(phraseOne, phraseTwo, phraseThree, phraseFour);
            continue;
        case 2: //Calls to signature submenu.
            signatureMenu(signature, signatureNew);
            continue;
        case 3: //Calls to email submenu.
            emailMenu(phraseOne, phraseTwo, phraseThree, phraseFour, signatureNew);
            continue;
        case 4: //Calls to information about the program.
            about();
            continue;
        case 5: //Exits the program.
            cout << "Goodbye...." << endl;
            exit = true; //Sets exit condition true.
            break;
        default: //If a valid option is not entered, display error.
            cout << "Please select a valid option." << endl;
    } //End switch.

    } while (!exit); //End do-while when exit condition is true.

    return 0;
}


The only difference I can see is that its in a do-while loop in the second bit of code. I thought it might be that the error detection does not work with the switch but it doesn't work in other places of the code either... seemingly anytime there is a nested check.

Can anyone provide some assistance in determining what is causing the loop, or why? I imagine its something simple with the logic of the do-while, but I can't figure it out.

Or if someone has a better idea of a quick error validation function, I'm open to ideas.
Last edited on
Hello confundido,

Try this:
1
2
3
4
5
6
7
8
9
10
11
12
cin >> choice; //Store menu choice in choice integer.

while (!cin) //WHILE LOOP FOR ERROR DETECTION
{
	cin.clear();  // <--- Resets state bits on stream.
	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>. Clears input buffer.
	
	cout << "\nInvalid choice, please try again: ";
	cin >> choice;
}

std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>. Clears input buffer. 

There is no need to clear the input buffer after your first "cin". Should you enter the while loop it will be done there otherwise clear the input buffer after the loop if needed.

Also there is no need to clear the input buffer unless there is a "std::getline()" that follows. This could be somewhere else in the program or even in another function or file. Of course it does not hurt to clear the buffer if that is what you feel comfortable with.

You while condition of (!cin >> choice) starts by waiting for a second input, but if "cin" has failed on the first input this is pointless because the "cin" will not work at this point. All you need to check for is the state of "cin" and "!cin" is checking the good bit which can be changed by any of the other state bits.

The "ignore" statement I changed is more portable, but there is nothing wrong with what you have done.

Hope that helps,

Andy
Thank you, yes it seemed to be just the cin.ignore after the initial cin that was causing the problem.

Our teacher has been having us just get into the habit of doing a cin.ignore after ever cin or cin.get as a standard practice, and it seemed to have caused me a problem here.

Thank you.
Hello confundido,

If your program contains only formatted input, i.e., std;:cin >> aVariable; there is no need to clear the input buffer. The next std;:cin >> aVariable; will over look the "\n" and read what comes after that.

When you need to clear the input buffer is when you mix formatted and unformatted input as in:
1
2
3
4
std::cin >> aVariable;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.

std::getline(std::cin, aVariable);

In this case without clearing the input buffer the "getline" line 4 will not wait for input from the keyboard, but read the "\n" from the input buffer and continue on.

The way "std::getline" works it will read everything from the input buffer including the "\n" and then discard the "\n" leaving the input buffer empty.

Hope that helps,

Andy
If your program contains only formatted input, i.e., std;:cin >> aVariable; there is no need to clear the input buffer.

This is not correct.

The op is using the insertion operator>> to retrieve numeric values. If someone enters a non-numeric value the stream will fail and these "bad" values will remain in the input buffer and must be "removed" after clearing the failure flags before trying to get a "correct" entry.

1
2
3
4
5
6
7
8
9
10
11
12
// The next two lines are not needed.
//    cin >> choice; //Store menu choice in choice integer.
//    cin.ignore (100, '\n'); //Clear input.

    while (!cin >> choice) //WHILE LOOP FOR ERROR DETECTION
    {
        cin.clear();
        cin.ignore(100, '\n');  // This is were you need to put the ignore.
        cout << "\nInvalid choice, please try again: ";
//        cin >> choice;  // Not needed here, you're already trying to get input in the loop condition.
//        cin.ignore(100, '\n');  // Wrong place.
    }


Topic archived. No new replies allowed.