cin.fail() is still executing when there's an integer in the front of the input.

Why does the code below still execute and move on to the next line when it's not supposed to. Here's an example, when amount_input is 2w, the program still executes and prints out 2. Shouldn't the program loop the while loop and print out Enter number only since there's a character in the input and the code below only accepts integer value? The program does however execute properly if amount_input is w2. I partially see the error, and that the program seems to read the first letter or integer of the input and executes it accordingly, but is there a way to make it so that no matter the case if there's a character in an integer input, the program will tell the user to re-enter?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void option_1()
{
	int amount_input;
				
	cout<<"Enter the amount of cake"<<endl;
	cin>>amount_input;
	while(cin.fail())
	{
	  cin.clear();
          cin.ignore(INT_MAX, '\n'); 
       	  cout<<"Enter number only\n";
       	  cin>>amount_input;
	}
	cout<<amount_input;
}
cin>>amount_input reads an integer. you typed 2. success.

the trusted way to do this is to read a string, usually a getline, and attempt to convert that to an integer. "2w" converted from a string will not succeed.
Last edited on
@jonnin what can I do when the conversion from string to int isn't successful, do I use try catch? Thanks for the help btw
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
#include <iostream>
#include <string>
using namespace std;

int getMyInt()
{
   size_t pos;
   string test;
   int i;

   cout << "Input an integer (or 0 to end): ";
   getline( cin, test );

   try
   {
      i = stoi( test, &pos );           // pos is next position in string
   }
   catch( ... )                         // Failure to convert anything
   {
      cout << "Not convertible to int\n";
      return getMyInt();
   }

   if ( pos < test.size() )             // Additional chars (including blanks) after
   {
      cout << "Spurious characters at end\n";
      return getMyInt();
   }
   
   return i;
}


int main()
{
   int value = 1;
   while ( value != 0 )
   {
      value = getMyInt();
      cout << "Integer is " << value << '\n';
   }
}


Input an integer (or 0 to end): 2w
Spurious characters at end
Input an integer (or 0 to end): 1e10
Spurious characters at end
Input an integer (or 0 to end): 0.3
Spurious characters at end
Input an integer (or 0 to end): 0x10
Spurious characters at end
Input an integer (or 0 to end): e
Not convertible to int
Input an integer (or 0 to end): 42
Integer is 42
Input an integer (or 0 to end): 0
Integer is 0



jonnin wrote:
attempt to convert that to an integer. "2w" converted from a string will not succeed.

Unfortunately, @jonnin, that's not true. stoi(), when supplied with "2w", will 'convert' it successfully to 2.
Last edited on
Hello mrtammy2008,

When I look over the responses I feel as you do not have a good understanding of cin >> amount_input;.

To start with cin >> amount_input; also known as formatted input, and my experience has been it works best when the variable is defined as a numeric variable, tells "cin" to expect a number. So, when you key in 2 enter everything is fine. When you input something like "2w" it will extract the "2" into the numeric variable and leave the "w" and new line in the input buffer. This also means it will extract the number until it finds something that is not a number like "w", a white space or a new line.

That is why when you enter "2w" "cin" does not fail because it is able to put a number into the variable until it finds something that is not a number.

The while loop works when you enter something that is not a number. Which means that you enter a letter when the formatted input is expecting a number.

Also I would use while (!std::cin). Bear with me here because I do not use using namespace std;. This is a broader approach for checking the status of "std::cin". This is checking the status if the "good" bit which will be changed when any of the other state bits are set.

What is inside the while loop is fine.

The try/catch example from lastchance is good. A little more involved than I am use to. But the line i = stoi( test, &pos ); is much the same as formatted input. It will extract a number from a string until it finds something that is not a number like a letter, white space or a new line. If I understand correctly a period in a floating point number will read the number, but a period after a number is considered non numeric.

My use of the try/catch is a bit more simple.
1
2
3
4
5
6
7
8
try
{
	i = stoi(test);
}
catch (const std::exception& e)
{
	std::cout << "\n  " << e.what() << '\n' << std::endl;
}

Like lastchance's example what is in the () will catch any exception with the difference being that you can see what the exception is. With a try/catch you can have multiple catch blocks each tailored to the exception thrown. First you need to know what exception has been thrown.

In the past I have used this code and it has worked well for what I was doing. For the future I will have to work through lastchance's code to better understand how it works.

Should I have something wrong, someone let me know.

Hope that helps,

Andy
Registered users can post here. Sign in or register to post.