views:

154

answers:

5

How would I check if the input is really a double?

double x;

while (1) {
    cout << '>';
    if (cin >> x) {
        // valid number
        break;
    } else {
        // not a valid number
        cout << "Invalid Input! Please input a numerical value." << endl;
    }
}
//do other stuff...

The above code infinitely outputs the Invalid Input! statement, so its not prompting for another input. I want to prompt for the input, check if it is legitimate... if its a double, go on... if it is NOT a double, prompt again.

Any ideas?

A: 

I would use scanf instead of cin.

The scanf function will return the number of matches from the target string. To make sure a valid double was parsed, make sure the return value of scanf is 1.

Edit:
Changed fscanf to scanf.

advait
I want to read from the command line... isn't `fscanf` for reading from a `FILE`?
Hristo
The question is about how to do it using `cin`.
casablanca
`scanf` will provide the same functionality except will be read from `stdin` instead of an arbitrary file object.
advait
You don't "read" from the command line, it comes in as the `argv` parameter to `main()`. Both `scanf` and `cin` read from standard input, and `cin` is definitely preferred in C++ programs as it is type safe. `fscanf` can read from any file (including `stdin`), the C++ equivalent is `ofstream fin(filename); fin >> x;`. `cin` is a pre-created stream that acts on standard input.
Ben Voigt
@Hristo - `scanf` reads from the standard input stream which is exactly what `cin` reads from. Neither read from the "command line".
D.Shawley
Yes I know `scanf` reads from the standard input stream, but thethimble initially recommended `fscanf`. Phrasing it as "command line" seems like a simple way to get my point across.
Hristo
scanf is c though, and the question is tagged c++
starcorn
+1  A: 

failbit will be set after using an extraction operator if there was a parse error, there are a couple simple test functions good and fail you can check. They are exactly the opposite of each other because they handle eofbit differently, but that's not an issue in this example.

Then, you have to clear failbit before trying again.

As casablanca says, you also have to discard the non-numeric data still left in the input buffer.

So:

double x;

while (1) {
    cout << '>';
    cin >> x;
    if (cin.good())
        // valid number
        break;
    } else {
        // not a valid number
        cout << "Invalid Input! Please input a numerical value." << endl;
        cin.clear();
        cin.ignore(100000, '\n');
    }
}
//do other stuff...
Ben Voigt
this is still causing the infinite loop to print the `Invalid Input!`... its not prompting for another input.
Hristo
What does the `cin.ignore()` do?
Hristo
Same thing as casablanca's loop, it throws away all characters up to and including the newline to get rid of whatever non-numeric data caused the first extraction to fail.
Ben Voigt
+2  A: 

Try this:

while (1) {
  if (cin >> x) {
      // valid number
      break;
  } else {
      // not a valid number
      cout << "Invalid Input! Please input a numerical value." << endl;
      cin.clear();
      while (cin.get() != '\n') ; // empty loop
  }
}

This basically clears the error state, then reads and discards everything that was entered on the previous line.

casablanca
is this inside the `while(1)` loop?
Hristo
Yes, inside your existing loop. I've just reproduced the inner part.
casablanca
Ok that works. Can you explain the logic behind the empty loop? What exactly is going on in there? What does `get()` do?
Hristo
Since `cin >> x` expects a number, you need to clear any invalid input that was previously entered. `get()` simply reads one character at a time, and the loop continues until it reaches the end of the line.
casablanca
Thank you. That makes sense... seems inefficient but since I'm dealing with a small number of characters, reading to the end of the line won't be difficult. I know there is a difference between Windows and UNIX in ending a line... something like `\r` in Windows? Will your solution work in both environments?
Hristo
Instead of `while(cin.get() != '\n');`, I'd just use `cin.sync();`. It's more readable in my opinion.
chaosTechnician
what does `cin.sync()` do?
Hristo
In UNIX, it's a `\r\n`, so there's still a `\n` at the end. So yes, it will work.
casablanca
@casablanca... Thanks!
Hristo
@Hristo: From http://cplusplus.com/reference/iostream/istream/sync/ It "synchronizes the buffer associated with the stream to its controlled input sequence. This effectively means that the unread characters in the buffer are discarded."
chaosTechnician
@chaosTechnician: +1. I had no idea there was a ready-made method to do this. @Hristo: I just searched for `sync` and here's a [reference](http://www.cplusplus.com/reference/iostream/istream/sync/). I guess you could replace the `while` loop with a single call to `sync` then.
casablanca
@chaosTechnician, cin.sync() doesn't work for me when I try this example. the while(cin.get() != '\n'); does though. Any idea why?
Mahmoud Abdelkader
@Mahmoud: When you say it doesn't work, what is it doing? The above code (with `sync()` used instead of the loop) works fine for me using VS2008's compiler and GCC. Are you replacing more than just the loop with `sync()` or using a non-standard compiler?
chaosTechnician
I'm using g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3. I copy and pasted the Hristo's code and tried it and it still giving me an infinite loop of 'Invalid Input! Please..."
Mahmoud Abdelkader
@Mahmoud: are you missing the `cin.clear();` line?
chaosTechnician
No, it's written before: cin.sync(); Here's a snippet of the code:int main(int argc, char *argv[]){ double x; while (1) { cout << '>'; if (cin >> x) { break; } else { // not a valid number cout << "Invalid Input! Please input a numerical value." << endl; cin.clear(); cin.sync(); // while(cin.get() != '\n'); } } cout << "you entered: " << x << endl; return 0;}
Mahmoud Abdelkader
A: 

One way is to check for floating number equality.

double x;

while (1) {
    cout << '>';
    cin >> x;
    if (x != int(x)) {
        // valid number
        break;
    } else {
        // not a valid number
        cout << "Invalid Input! Please input a numerical value." << endl;
    }
}
Dave18
how does this check for type `double`?
Hristo
This just checks if the input had a fractional part, which is probably not what was meant by the question.
Ben Voigt
Yeah, most of us know what Hristo meant but this answer does address the question he asked: "How would I check if the input is really a double?" Interpreting that as, "I assume I'm getting numbers, how do I ensure they aren't whole numbers?" makes this a perfectly useful answer. No need to downvote, imo.
chaosTechnician
A: 

Saw an interest post over on Velocity Reviews using templates.

Source: http://www.velocityreviews.com/forums/showpost.php?p=3946881&amp;postcount=12

#ifndef TYPEOF_H
#define TYPEOF_H

#include <string>

namespace Tools
{
  using namespace std;

  template<class T> static string typeof() { return "unknown"; }
  template<> static string typeof<bool>() { return "bool"; }
  template<> static string typeof<int>() { return "int"; }
  template<> static string typeof<double>() { return "double"; }

  template<class T> static string typeof(const T& t) { return typeof<T>(); }
}

#endif

Which could then be used like so:

#include "Typeof.h"

void main()
{
  std::string type = "";

  double d = 0.0;
  type = Tools::typeof(d);
}
TomFLuff
And this related to the question how exactly...?
Georg Fritzsche