cin fails to read - Infinite loop after reading from istandard

Hello folks,

I'm tring to understand what is happening here.
I have this simple code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...

int number;

do{
 try{     
  cout << "Enter number [-1 to exit]:";
  cin >> number;//<-Won't prompt here for new imput if user type a letter by mistake
     cout << "\n Read Number, " << n << ".\n";
     
   }catch(const std::string& ex){
     cout<< "Ups...! "<< endl<< ex;
   } 
     
  }while( number != -1 );


So let me understand why:
* If the user type a character by mistake the program will not prompt for new input.
* If the user in the very first iteration types a number, and in the next iteration types a char, the var (number) will keep the first typed value and cin will not prompt again for a value.

In both scenarios it causes a infinite loop and no exception is thrown.

Thank for your comments...!

Jose.
> If the user type a character by mistake the program will not prompt for new input

Because the initial input was rejected (a character is not an integer, and you're using integer-only input at line 3). It is there inside cin, waiting for you to either discard it or to reprocess it.

> If the user in the very first iteration types a number, and in the next iteration types a char, the var (number) will keep the first typed value

That's the older C++ behavior: when the input is rejected, the variable keeps its original value. Newer compilers change it to zero when that happens. But either way, the input is rejected and needs to be reprocessed or discarded before any new input can take place.

By the way, since nothing is throwing any strings in your code, try/catch does nothing.
Last edited on
Yea try/catch in C++ isn't as simple as it is in C#. You must actually throw most exceptions although you can catch any exception by using the elipsis (...)

Your best bet is to read in character by char and try to cast them to an int. That way your program won't fail when an invalid int is entered.

You can use the library method isdigit(char c) to determine if a char is a digit. If it is, you can cast to an int using the C library method atoi.

You could also check is the stream failed and manually clear it yourself. Let me know if you need some example code.


EDIT - just try this, it's as simple as it gets for your situtation.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main()
{
	int input;
	
	do 
	{
             cin >> input;

	     if (!cin) 
	     {
                  cin.clear();
		  cin.ignore(256, '\n');
	     }
	}
	while (input != -1);
 
	return 0;
}
Last edited on
Your best bet is to read in character by char and try to cast them to an int. That way your program won't fail when an invalid int is entered.

You can use the library method isdigit(char c) to determine if a char is a digit. If it is, you can cast to an int using the C library method atoi.


Horrible suggestion. In the code, input is never initialized to any value, but the loop depends on it's value (which is the wrong thing to loop on anyway.)

Hopefully the following is more illustrative.

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
55
56
57
58
59
60
61
#include <sstream>
#include <string>
#include <iostream>
#include <limits>
#include <stdexcept>


// utility function.  Keeps the loop logic
// a little cleaner in the get_int functions.
template <typename T>
std::istream& get_input(char const* prompt, T& input)
{
	std::cout << prompt ;
	return std::cin >> input ;
}

// get an int directly.
int get_int_1(char const* prompt)
{
	int input ;
	while ( !get_input(prompt, input) )
	{
		// clear error state:
		std::cin.clear() ;

		// discard the line of input:
		std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n') ;
	}
	return input ;
}

// read in a string and parse the string for an int.
int get_int_2(char const* prompt)
{
	std::string input ;

	while ( get_input(prompt, input) )
	{
		std::istringstream is(input) ;

		int input_as_int ;
		if ( is >> input_as_int )
			return input_as_int ;

		std::cout << '"' << input << "\" is not valid.\n" ;
	}

	// A failure from get_input means something outside the normal realm of events 
	// for console input has occurred -- possibly stdin was redirected to a file,
	// and we ran into eof, for example.  Let's consider it exceptional.
	throw std::runtime_error( "Unexpected extraction error in get_int_2\n") ;
}

int main()
{
	int anInt = get_int_1("Enter a number: ") ;
	std::cout << anInt << " is the number you entered.\n" ;

	anInt = get_int_2("Enter another number: ") ;
	std::cout << anInt << " is the second number you entered.\n" ;
}

Last edited on
^^^
Last edited on
Topic archived. No new replies allowed.