tags:

views:

767

answers:

9

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?

A: 

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").

Colen
And since conversion from string in C++ is easiest done using string streams, he's back to square one. Bad idea IMO.
sbi
+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).
Johannes Schaub - litb
@litb: How do they behave differently?
sbi
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.
Johannes Schaub - litb
@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.)
sbi
My "you" was directed at Colen :) In any case, i agree that some code would have been better. But it doesn't seem worth a -2 (just because code was missing?). So i upped him :)
Johannes Schaub - litb
+4  A: 
std::cout << "Enter doubles: ";
std::cin >> d1 >> d2 >> d3;

if(std::cin.fail())
{
    // error!
}
AraK
Primitive types such as double can't be NULL in Java either
Tyler McHenry
@Tyler Sorry, I am just a java newbie :)
AraK
@Tyler I removed the wrong part about Java, Thanks.
AraK
+3  A: 

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.

sbi
+2  A: 

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.

John Millikin
+1  A: 

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
}
Evan Teran
+2  A: 

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.

Tyler McHenry
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**.
sbi
You're right. It should be !fail. Fixed.
Tyler McHenry
@Tyler: down-vote removed. `:)`
sbi
+2  A: 

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.

Naveen
+10  A: 

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

Johannes Schaub - litb
@litb: That table is great! +1
sbi
I already upvoted this man, I wish a can upvote it again ;)
AraK
A: 

eehm.. i have a problem... when i try to use the cin >> yesno for my program it doesnt work :S the program have to show me a message if i put in 'a' but it gives nothing...

Ask a new question, provide code, compile errors if any, and the output you get, along with the desired behavior.
GMan