Nick Sinas
Nick Sinas

Reputation: 2634

Check if input is blank when input is declared as double [C++]

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?

Upvotes: 3

Views: 6646

Answers (8)

sbi
sbi

Reputation: 224079

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.

Upvotes: 3

Johannes Schaub - litb
Johannes Schaub - litb

Reputation: 507005

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

Upvotes: 11

Tyler McHenry
Tyler McHenry

Reputation: 76660

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.

Upvotes: 3

Naveen
Naveen

Reputation: 73443

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.

Upvotes: 2

Khaled Alshaya
Khaled Alshaya

Reputation: 96869

std::cout << "Enter doubles: ";
std::cin >> d1 >> d2 >> d3;

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

Upvotes: 4

Evan Teran
Evan Teran

Reputation: 90442

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
}

Upvotes: 1

John Millikin
John Millikin

Reputation: 200806

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.

Upvotes: 2

Colen
Colen

Reputation: 13908

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

Upvotes: 0

Related Questions