while validation loop can't handle letter inputs

Hey guys! I'm moving up the ol' C++ knowledge ladder. I'm betting only enlightenment and joy awaits at the top ... right?

Hey, so something that I've had an issue with is infinite loops. I'm not always sure of the most effective way to close them. I'll give you an example. The while validation loop below works perfectly when a user enters a number. But - and maybe I make things too complicated - it goes into infinite loop hell if I experiment by putting a letter in the user input (i.e. 'h').

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main()
{    
    int days;
    std::cout << "Total number of days spent on trip? ";
    std::cin >> days;
    
    while (days < 1)
    {
        std::cout << "**That is not a valid input**\n";
        std::cout << "Total number of days spent on trip? ";
        std::cin >> days;
    }
    
    std::cout << days << endl;

    return (0);
}


I've tried things like static_cast<int>(days) to make sure the program keeps thinking it's an integer, but that didn't work. I'm still limited in knowledge so forgive any remedial methods I may be using.

How do I stop the infinite while loop when a user throws letters at it?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <limits>

int main()
{    
    int days;
    std::cout << "Total number of days spent on trip? ";

    // while input extraction is not successful, or the input isn't valid 
    while (!(std::cin >> days) || days < 1)
    {
        std::cout << "**That is not a valid input**\n";
        std::cout << "Total number of days spent on trip? ";

        // clear the error state and remove the input that caused cin to
        // enter an error state in the first place.

        std::cin.clear() ;
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n') ;
    }
    
    std::cout << days << std::endl;
}
Huh. Limits. I'll make sure I read up on that and get very familiar with it.

I also see that you used cin.clear(). I had a feeling my program was partly in a loop because the variable just retained it's incorrect value and just went on and on and on. I guess I was kinda on the right track.

I think I got it. I really appreciate you taking the time!
The problem is that your code did not consider the possibility that the user can type in anything.

Since days is an integer, cin >> days; means that the computer is looking to parse an integer value. Letters are not an integer, so the cin istream is signaled to a failed state and no other input operations will work on it.

Cire's code checks first that the input was successful and only then that it was valid -- if if was neither, it displayed the complaint and then:
1) "clear"ed, or reset the error on the istream,
2) removed all the user's bad input

Hope this helps.
LazyTechGuy wrote:
Huh. Limits. I'll make sure I read up on that and get very familiar with it.


Not much reason to get real familiar with it right at the moment, but it's good to be aware of it.

std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); is the canonical way to discard a line of input, but it could just as well have been some arbitrary number such as 1024 as the first argument to ignore. It would have the same effect on most user-supplied input (although it might make a difference if std input was being fed by a file (perhaps via a pipe) with lines larger than 1024 bytes.)

The thing to take away is that once a std::istream object, such as std::cin, enters an error state it stays in an error state until you clear it, and that input that puts the std::istream into an error state will still reside in the buffer until you remove it.
Last edited on
Topic archived. No new replies allowed.