Why does cin get skipped?

closed account (Ey80oG1T)
I have this short snippet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main()
{
    cout << "User Input... ";

    int userChoice = NULL;
    cin >> userChoice;

    if (userChoice == 1)
    {
        cout << "1";
    }  
    else
    {
        cout << "Resetting... ";
        main();
    }
}



When I input a number (other than 1), then the loop resets, and asks me to input another number.

1
2
3
User Input... 10
Resetting... User Input... 15
Resetting... User Input... _


Nothing to out of the ordinary yet. However, when I input a string, I expect the code to go the the else statement, loop back to the start, and ask for another value. But that's not the case.

1
2
User Input... string
Resetting... User Input...Resetting... User Input...Resetting... User Input...Resetting... User Input...Resetting... User Input...Resetting... User Input...Resetting... User Input...Resetting... User Input...Resetting... User Input...Resetting... User Input...Resetting... User Input...Resetting... User Input...Resetting... User Input...


It just repeats infinitely! Does anyone know why this is happening and how to fix it?
Last edited on
do not call main via recursion, this is not allowed in standard C++ and its an unstable extension in some compilers, other support it correctly, but its not safe.

use a loop if you want to loop.

if you want to do it with recursion, make another function and call it from main. That is supported.
Last edited on
closed account (Ey80oG1T)
I don't think calling main via recursion is causing the problem. I tried other loops like the while and goto loops, and they still produce the same result!

Why is this?
Last edited on
Calling main is not unstable. It is illegal.

Use a loop. (The goto is not a loop.)
1
2
3
4
5
6
7
8
while ( true ) {
}

do {
} while ( true );

for ( ; true ; ) {
}

But, do you really want to run forever?
closed account (Ey80oG1T)
First, yes, I do. I'm making a sort of game and I need to loop my code infinite.

And second, I tried all that, but the output is the same infinite result. So I don't think it's the loop, but rather the code. It seems that cin is getting skipped over...
Last edited on
We can't see the code that you have now.
The following works so long as you type numbers. If you type a letter it will likely loop forever in a crazy fashion. If that bothers you, you need to read as a string instead of an integer; this will prevent it from doing that (second version), but if you do that, you can't compare against 1 you have to compare against "1" instead (the string version). It is totally normal for the below program to go haywire if you type letters where a number was expected: you have to either not do that or change the code so it can handle invalid input. Does that answer your question?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20


int main()
{
	while(true)
	{
    cout << "User Input... ";
    int userChoice = 0; //NULL is for pointers, do not use here even though is zero. 
    cin >> userChoice;
    if (userChoice == 1)
    {
        cout << "1\n";
		return 0; //how to stop if they type 1, my take on your needs??
    }  
    else
    {
        cout << "Resetting... \n";    
    }
  }
}


better:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main()
{
	while(true)
	{
    cout << "User Input... ";
    string userChoice = ""; 
    cin >> userChoice;
    if (userChoice == "1")
    {
        cout << "1\n";
		return 0; //how to stop if they type 1, my take on your needs??
    }  
    else
    {
        cout << "Resetting... \n";    
    }
  }
}
Last edited on
closed account (Ey80oG1T)
Keskiverto

You don't need to see everything. The snippet I provided should be enough. Don't worry, it's basically the same.

Jonnin

Interesting point - making the input a string. I'll try that!

However, I'm curious to why the cin gets skipped if you input a string. Even with the code you provided, if I input a string, it goes haywire. But why?
Last edited on
it has to do with how cin works. You tried to read an int where there was not one and that put the stream in a bad state, and when that happens you can detect it and clear the bad data and so on but that is a big wad of unnecessary code; its easier to just read pretty much everything as a string, see if its valid, and then proceed once you get something you can use. Once the stream is in a bad state, reading from it in a loop does not do well; it keeps trying to read, the data is still there because it didn't clear it when the error happened, and it gets into a snarl. it effectively reads the junk you typed, errors but not crashes, loops again, the stream has data as if you typed something, so it tries to read it again.... and again... and again...

the second one should work for you.
you are correct, that main recursion was not the issue here, but do not do that; its one of the least stable of the quasi-supported extensions.
Last edited on
closed account (Ey80oG1T)
I see... so would clearing the user's input before the loop make a difference?

And what if I wanted to do arithmetic calculations? Is there a way to make it work using an integer variable?
Last edited on
Here
1
2
    int userChoice = NULL;
    cin >> userChoice;

If you don't enter an integer, the input fails. This sets the status of the cin stream to 'fail'.
You need to do two things to rectify that:
1. reset the error flag
2. discard the invalid characters which are still waiting in the input buffer.

Also, calling main() is illegal. Use a loop instead.

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
#include <iostream>

using namespace std;

int main()
{
    while (true)    // Loop forever
    {
    
        cout << "User Input... ";
    
        int userChoice = 0;
        cin >> userChoice;
        
        if (!cin)                      // did the input fail?
        {
            cin.clear();               // reset error flags
            cin.ignore(1000, '\n');    // discard characters from input buffer
        }
    
        if (userChoice == 1)
        {
            cout << "1\n";
        }  
        else
        {
            cout << "Resetting... \n";
        }
    }
}
Last edited on
closed account (Ey80oG1T)
Oh hey, that works!

Thanks
I see... so would clearing the user's input before the loop make a difference?

And what if I wanted to do arithmetic calculations? Is there a way to make it work using an integer variable?


it needs to be in the loop. You should check the status and fix the problem *every time you read an integer from cin* ... so every iteration of the loop would check the stream status and fix it if it was screwed up. Its better to read as a string for this example: its a lot of unnecessary work.
you can convert a legit integer string to an int. intvar = stoi(stringvar) is the way, but you may want to iterate all the letters of the string to check isdigit() on each one, if you care that much. Here, its just a flag, and its fine to use it as a string without all that extra. But if you were doing math, and you wanted validation, the above is the way, OR, if you want it as integers, you can fail the stream and check it and reset it and get again until it was valid, letting the stream do the 'is it an integer' validation part for you ... either way works. I would prefer to let the stream fail (because I work with doubles and there are a number of valid formats like 1.0e3 or 1000 or 1.234 and more inputs accepted) but be aware that it does odd things if you type 123zzz and you want to be sure you understand how that is handled if you go that route.
Last edited on
closed account (Ey80oG1T)
Cool, thanks!
Topic archived. No new replies allowed.