15

I am writing this code for a homework assignment (just starting C++ so please go easy). We've just started while, do-while, and for loops today. The program runs fine except that if you enter a letter when the program asks for an integer, it loops infinitely. What is going on? (Code below) ***EDIT: To clarify, the part that is looping is: "The number you have entered is negative. Please enter a positive number to continue." But the user is not given a chance to enter another number. It just keeps printing this.

    #include <iostream>
using namespace std;

int main ( )
{
    //define variables
    int num1, num2, total;
    char answer1;

    do
    {
        //user enters a number
        cout << "\nPlease enter a positive number and press Enter: \n";
        cin >> num1;

        //check that the given num1 value is positive
        while (num1 < 0)
        {
            cout << "The number you entered is negative.\nPlease enter a positive number to continue.\n";
            cin >> num1;
        }

        cout << endl;

        //add the sum of 1 through num1 value
        num2 = 1;
        total = 0;
        while (num1 >= num2)
        {
            total = total + num2;
            num2 ++;
        }

        //tell the user the sum
        cout << "The total of all the integers\nfrom 1 to " << num1 << " is: \n";
        cout << total;

        //ask if the user wants to try again
        cout << "\n\nWould you like to try again with a new number?\nEnter y for yes or n for no.\n";
        cin >> answer1;
    } while (answer1 == 'y');   

    cout << endl;
    return 0;
}
user2907563
  • 151
  • 1
  • 1
  • 4

4 Answers4

14

This is how basic_istream works. In your case when cin >> num1 gets wrong input - failbit is set and cin is not cleared. So next time it will be the same wrong input. To handle this correctly you can add check for correct input and clear&ignore cin in case of wrong input. For example:

    #include<limits>

    //user enters a number
    cout << "\nPlease enter a positive number and press Enter: \n";
    do {    
        while(!(cin >> num1)) {
            cout << "Incorrect input. Please try again.\n";
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
        }
        if(num1 < 0) cout << "The number you entered is negative. Please enter a positive number to continue.\n";
    } while(num1 < 0);
Sergey
  • 406
  • 2
  • 6
1

When you enter a letter, the error state of cin is set and there won't be any further input possible before you call cin.clear(). In consequence, the statement cin >> num1 will not change the value of num1 and you loop forever.

Try this:

    while (num1 < 0)
    {
        cout << "The number you entered is negative.\nPlease enter a positive number to continue.\n";
        cin.clear();
        cin >> num1;
    }

EDIT:

Thanks to Lightness for pointing this out. You should initialize num1 too:

int num1=-1, num2, total;
Axel
  • 13,939
  • 5
  • 50
  • 79
  • 1
    This is not sufficient. `num1` is not initialised and so a letter-entry does not guarantee to trigger this loop. – Lightness Races in Orbit Oct 22 '13 at 15:01
  • Seems like it was indeed triggered in the OP's example, but as you said it's not guaranteed. Thanks. – Axel Oct 22 '13 at 15:05
  • [Some implementations set `num1` to `0` on error](http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01262_source.html#l00171) ([or do they?!](http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01288_source.html#l02048)), but it's not guaranteed. – Lightness Races in Orbit Oct 22 '13 at 15:06
  • The illegal character which triggered the error wasn't extracted, so you'll get it as the first thing in your `>>` after the clear, setting the error again. You need to resynchronize the input in some way. – James Kanze Oct 22 '13 at 15:06
  • @LightnessRacesinOrbit This is something which has changed in C++11. Pre C++11, it was guaranteed that a failing `>>` (for numeric values) did not modify the destination. In C++11, it is guaranteed that it will, setting it to 0 for a format error, and +/- the max value for overflow. – James Kanze Oct 22 '13 at 15:10
  • @JamesKanze: I can't find that wording. Where is it please? – Lightness Races in Orbit Oct 22 '13 at 15:12
  • Found it at 22.4.2.1.2/3, under stage three. I would still recommend not assuming anything about `num1` after failure, but apparently in C++11 it will be 0, and in C++03 it [probably] won't be. – Lightness Races in Orbit Oct 22 '13 at 15:16
  • @JamesKanze: As a breaking change, this should have been listed under C.2.15, but it's not >. – Lightness Races in Orbit Oct 22 '13 at 15:18
  • @LightnessRacesinOrbit I rather agree with you about not assuming anything. Rather that `num < 0` in his `if`, I'd use `!cin`. – James Kanze Oct 22 '13 at 16:41
  • @Axel: You almost fixed it, but the loop still won't be hit if the input is non-numeric. – Lightness Races in Orbit Oct 22 '13 at 16:58
  • In the meantime there's an answer posted by Sergey Kolotienko that should fix it. – Axel Oct 22 '13 at 19:58
1

This answer should solve your problem. Basically you are trying to read a character from the stream and it can't be parsed to an int, so the stream is left in an error state.

You should check for an error, clear it and react accordingly.

Community
  • 1
  • 1
ghembo
  • 400
  • 1
  • 7
  • 1
    The text "this answer" doesn't explain how to solve the problem. I know it's a link, but if you're going to refer to some extra resource you ought to quote the important passages. – Lightness Races in Orbit Oct 22 '13 at 15:04
0

You can use a "char" datatype as an input from the user then use "static_cast("variable name");

char input;
int choose;
cin >> input;
choose = static_cast<int>(choose) - 48;///then use 'if' statement with the variable 'choose'
Al-Hanash Moataz
  • 385
  • 4
  • 14