1

I am sure I am missing on a very simple thing here. My code looks something like this. It just checks what is the type of triangle.

try { double FirstSide,SecondSide,ThirdSide; cout<<"Enter the first side: "; cin>>FirstSide; if(cin.fail()) { throw invalid_argument("Your input doesn't look to be a number."); } if(FirstSide > numeric_limits<double>::max() || FirstSide<0) { throw invalid_argument("Input is out of range."); } cin.ignore(); // Used afterwards, just to check cout<<"Enter the second side: "; cin>>SecondSide; if(cin.fail()) { throw invalid_argument("Your input doesn't look to be a number."); } if(SecondSide > numeric_limits<double>::max() || SecondSide<0 ) { throw invalid_argument("Input is out of range."); } cout<<"Enter the third side: "; cin>>ThirdSide; if(cin.fail()) { throw invalid_argument("Your input doesn't look to be a number."); } if(ThirdSide > numeric_limits<double>::max() || ThirdSide < 0) { throw invalid_argument("Input is out of range."); } // Check for equilateral if(FirstSide == SecondSide == ThirdSide) { cout<<"The triangle is equilateral. "; } else if(FirstSide == SecondSide || SecondSide == ThirdSide || FirstSide == ThirdSide) { cout<<"The triangle is isosceles."; } else { cout<<"The triangle is scalene. "; } } catch(invalid_argument& error) { cerr<<error.what()<<" Will now exit. "<<endl; return -1; } 

If I input 2p, I get the output: Enter the second side: Your input doesn't look to be a number. Will now exit.

Since the input is invalid for FirstSide, Enter second side: should not actually be printed. I am aware of the fact that compiler might be taking 2 for FirstSide and trying to assign p to SecondSide and hence the behaviour. If I ignore the values in stream (by using cin.ignore(), I actually get no error).

My question is how do I get my input correct for such cases like 2p or 1k?

Thanks.

EDIT:

Another question has popped up from the comments, How is the FirstNumber > numeric_limits<int>::max() comparison actually working if the value has already been assigned to FirstNumber ? Reference: https://msdn.microsoft.com/en-IN/library/hh279678.aspx

8
  • I am not sure, whether the comparison SecondSide > numeric_limits<int>::max() makes sense. Once the value is assigned to a int, it can only be < = numeric_limits<int>::max() and the comparison will always return true. Commented Aug 4, 2015 at 10:52
  • btw, your question would be much nicer if you could remove redundant stuff. Your code is basically doing the same thing 3 times. If you can fix it once, the other cins are also fixed, so there is no need to include it in an mcve. Commented Aug 4, 2015 at 10:55
  • @tobi303, I removed it and gave it a very very large number. No exception thrown. Program behaving incorrectly. Check out this link: msdn.microsoft.com/en-IN/library/hh279678.aspx Commented Aug 4, 2015 at 10:56
  • hm... seems like I was wrong, but honestly I am not convinced yet. As this msdn example is on error handling rather than numerical limits specifically, the example might be not the best demonstration of using numeric limits. I mean (by definition) the maximum value an int can hold is numeric_limits<int>::max(), so I dont get how this comparison can make sense. What happens if you use this check and type a large number? Commented Aug 4, 2015 at 11:05
  • @tobi303, If I type a large number and use this check, It throws the correct exception and works fine. Commented Aug 4, 2015 at 11:06

2 Answers 2

1

Using operator>>(double &) will first skip any whitespace characters, and then read character by character until a character is found that is not part of a number (e.g. a p or x, but not an e in case of double). This character is left inside the stream and the until then converted number returned. No error or failure is indicated.

(Example here, unfortunately I couldn't find formal proof for my argument.)

To achieve the desired behaviour, you need to split reading and converting:

  1. Read a token, probably terminated by whitespace, and
  2. convert it into the desired value.

.

double read_side(std::istream & in) { std::string token; std::string::size_type next; in >> token; double result = std::stod(token, &next); if (next != token.size()) { throw std::invalid_argument("trailing characters"); } return result; } 

Live example here.


I just noticed that you're now using std::numeric_limits<double>::max(), so the following does no longer apply to your code.

Considering your question about the comparison: Your variables are of type double, so when you compare them to an integer value, that integer will first be converted to a double:

[...] if either operand is double, the other shall be converted to double.

[N4431 §5/10.3]

And a double is able to store larger values than std::numeric_limits<int>::max().

Sign up to request clarification or add additional context in comments.

Comments

0

cin.fail() returns true if the last cin call failed. Consider the input 2p 3p 4p. This will work if you use cin.ignore() in between readings. FirstSide will be 2, SecondSide will be 3 and ThirdSide will be 4.

You could try clearing the stream and prompt the user for another input instead of throwing an exception.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.