3

I have three variable declared as doubles:

double Delay1 = 0;
double Delay2 = 0;
double Delay3 = 0;

I Then get their values from the user:

cout << "Please Enter Propogation Delay for Satellite #1:";  
cin >> Delay1;
...

But when I check these values to see if they are null (user just hit enter and did not put a number) it doesn't work:

if(Delay1  || Delay2 || Delay3 == NULL)  
      print errror...

This runs every time.
What is the proper way to check if an input that has been declared a double is blank?

8 Answers 8

11

Something like

cin >> Delay1;
if(cin) { ... }

won't work according to your specification, because cin will skip leading whitespace. The user can't just hit enter. He first has to enter some text. If he enters the following

3a

Then the input is read into the double, up to a, where it stops. cin won't find anything wrong, and leaves a in the stream. Often, this is enough error handling, i think. But if it's a requirement that you want to actually repeat when the user enters something like above, then you need a bit more code.

If you want to test whether the whole input up to the newline is a number, then you should use getline, read into a string and then try to convert to a number

string delay;
if(!getline(std::cin, delay) || !isnumber(delay)) {
  ...
}

The isnumber function can use a stringstream to test the string

bool isnumber(string const &str) {
  std::istringstream ss(str);
  double d;

  // allow leading and trailing whitespace, but no garbage
  return (ss >> d) && (ss >> std::ws).eof();
}

The operator>> will eat leading whitespace, and std::ws will consume trailing whitespace. If it hits to the end of the stream, it will signal eof. This way, you can signal the error to the user immediately, instead of erroring out at the next time you try to read from cin.

Write a similar function that returns the double or pass the address of a double to `isnumber, so that it can write the result in case of a successful parse.


It's also worth to have a look at the various error flags and how they relate to operator void*, operator!, good(), fail(), bad() and eof() which can be quite confusing:

            flag | badbit  |  failbit  |  eofbit
function         |         |           |
-----------------+---------+-----------+--------
op void*         |    x    |     x     |
-----------------+---------+-----------+--------
op !             |    x    |     x     |
-----------------+---------+-----------+--------
good()           |    x    |     x     |    x
-----------------+---------+-----------+--------
fail()           |    x    |     x     |
-----------------+---------+-----------+--------
bad()            |    x    |           |
-----------------+---------+-----------+--------
eof()            |         |           |    x
-----------------+---------+-----------+--------

There is an x if the respective bit influences the result. operator void* is used when converting to bool (if(cin) ...) while operator! is used for code doing !cin

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

1 Comment

@litb: That table is great! +1
4
std::cout << "Enter doubles: ";
std::cin >> d1 >> d2 >> d3;

if(std::cin.fail())
{
    // error!
}

2 Comments

Primitive types such as double can't be NULL in Java either
@Tyler Sorry, I am just a java newbie :)
3

What you need to check is the state of the input stream after you try to read in the double.

For example

cin >> Delay1;
if (!cin.fail()) {
  // Input was a double
} else {
  // Input was something that could not be interpreted as a double
}

You can write this more tersely as follows

if (cin >> Delay1) {
  // Input was a double
} else {
  // Input was something that could not be interpreted as a double
}

If the input fails, the value of Delay1 will not change, and so if you have not previously initialized it, it will be some arbitrary value. As has been pointed out, though, it will not become "NULL", since only pointers can be null, not value-types.

1 Comment

Note that there's a difference between if(is.good()) and if(is): The former also fails if is.eof() is true. In case of cin>>var; if (cin.good()) this would report an error even if var was read correctly, but happend to be the last thing in the input stream. This makes the first example wrong.
3

The way to check if stream input worked is to test the stream:

if(!std::cin) throw "Doh!";

Since operator>>always returns its left argument, this works, too:

if( std::cin >> Delay1 ) 
  good();
else
  bad();

Input streams will not alter the value if inputting fails. In your case, they will thus keep the random values they had before. You should never accept input without having checked the stream.

Comments

2

There's multiple things going wrong here.

First: to check whether parsing failed, use if (cin.fail()) { /* print error */ }.

Second: Delay1 || Delay2 || Delay3 will convert doubles to boolean values, and then logical-OR them together.

Third: == NULL will compare your boolean value (in this case false) to the pointer value NULL. I believe that this will always be true.

Comments

2

Your if condition is wrong. if(Delay1 || Delay2 || Delay3 == NULL) will be true if Delay is not equal to zero or delay2 is not equal to zero or Delay3 is zero. Surely that is not what you want. Also you should use 0 for primitive data types. Further, comparing the double values to an absolute value is always dangerous. You check whether the value is less than a small epsilon value.

Comments

1

just use the stream state, it will be in a fail state if it couldn't read a double.

if(!(std::cin >> Delay1 >> Delay2 >> Delay3)) {
    // error
}

Comments

0

I think you need to read the variable in as a string, then check to see if it's blank, then convert it to a double (and check if it's a valid double - the user might just have typed "hello").

6 Comments

And since conversion from string in C++ is easiest done using string streams, he's back to square one. Bad idea IMO.
+1'ed you. i think @colen has a point. see my answer for the code. This is not square one, because string streams behave different than a stream connected to stdin (especially, with regard to EOF).
@litb: How do they behave differently?
If you want to test whether there are any more characters after the number, then "cin" will possibly block waiting on input. a string stream, however, won't block.
@litb: Ah, I see. I hadn't considered checking for more input, as it doesn't seem to be a requirement, but you do have a point here. (OTOH, Colen's answer still doesn't help, as it doesn't tell how to do the actual conversion -- and besides such subtle issues as the one you brought up, that would require the same code as reading the values from std::cin directly. Or was your "you" directed at me? I'm somehwat confused by that.)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.