1

After spending a good amount of time researching input validation, I combined a few ideas and came up with this:

Function to check a string for a valid double...

bool isDouble(double& destination, string& source)
{ // 64 bit
  bool goodValue = false;

  if (!source.empty()) {
    errno = 0;
    char *garbage = nullptr;
    destination = strtod(source.c_str(), &garbage);

    if (*garbage == '\0' && errno != ERANGE)
      goodValue = true;
  }

  return goodValue;
}

Function to check a string for a valid 32 bit integer...

bool isLong(long& destination, string& source)
{ // 32 bit (base 10)
  const short BASE = 10;
  bool goodValue = false;

  if (!source.empty()) {
    errno = 0;
    char* garbage = nullptr;
    destination = strtol(source.c_str(), &garbage, BASE);

    if (*garbage == '\0' && errno != ERANGE)
      goodValue = true;
  }

  return goodValue;
}

Sample Implementation

using namespace std;

int main() {
  string buffer;
  double value;

  cout << "Enter a value: ";
  getline(cin, buffer, '\n');

  if (isDouble(value, buffer))
    cout << "Value: " << value << endl;
  else
    cout << "ERROR: Invalid input\n";

  return 0;
}

Can anyone comment on if I am overlooking anything with this approach?

That1Guy
  • 7,075
  • 4
  • 47
  • 59
  • This is already covered in the folliwng: [How to validate numeric input C++][1] [1]: http://stackoverflow.com/questions/514420/how-to-validate-numeric-input-c – Ren Oct 07 '11 at 22:47
  • @Ren, That solution doesn't deal with garbage in the buffer. –  Oct 07 '11 at 22:50
  • Please use `strtod( )`, which gives you a pointer to the end of the parsed value. Do not invent your own syntax-checker for floating-point values. A regex is total overkill. – Stephen Canon Oct 08 '11 at 22:12
  • @ephaitch It's pretty much OK. – FailedDev Oct 09 '11 at 19:20
  • @FailedDev When you say "pretty much" is there something I should consider or something I am missing? –  Oct 09 '11 at 19:36
  • @ephaitch I could not find an error at various nasty tests I performed. And you logic is sound. I think you don't miss anything. – FailedDev Oct 09 '11 at 19:37
  • @FailedDev Awesome! thank you very much for your help in this post and the other one. (= –  Oct 09 '11 at 19:38
  • @ephaitch Np. Maybe you should post and accept your own answer! :) – FailedDev Oct 09 '11 at 20:00

3 Answers3

1

I'm not sure about "the" correct way, but it's certainly not how I'd do it. First and probably most obvious, this chunk of code:

    for (i = 0, d = 0; i < BUFFSIZE && buffer[i] != 0 && buffer[i] >= '0' &&
             buffer[i] <= '9' || (buffer[i] == '.' && d == 0); i++)
            if (buffer[i] == '.') ++d;

is duplicated in a couple of places (at least I think the other instance is identical, and probably should be anyway).

Second, you don't appear to allow numbers like 1e23 or -1.2, which are usually accepted as floating point.

Offhand, I think I'd use strtod to attempt to convert the input. You can use its second parameter to detect whether a conversion reached the end of the input string (if not, you'll know at least part of the input wasn't accepted). You'll then (apparently) want to check that the returned value was in the desired range.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
1

Perhaps the strtod() function can be of help here, as it tells you how much has been converted:

const char * buf = get_raw_data(); // somehow

char * endptr;
const double value = strtod(buf, &endptr);

if (endptr != buf + std::strlen(buf))  { /* ... error ... */ }

As the source for buf you could tokenize your input with std::string token; std::cin >> token; or something like that and use token.c_str().

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
0

If it's an exercise you want, that's understandable. But otherwise, you can use istringstream to avoid reinventing the wheel:

#include <iostream>
#include <sstream>
#include <string>

using namespace std;

int main () {

  int n,val;
  string stringvalues;

  stringvalues = "3.14159254 f01fhasfljk";
  istringstream iss(stringvalues);

  float x,y;
  iss >> x;

  cout << x * 2 << endl;

  iss >> y;
  if ( ! iss.fail() )
    {
      cout << y * 2 << endl;
    }
  else
    {
      cout << "second value not a number..." << endl;
    }

  return 0;
}
user
  • 7,123
  • 7
  • 48
  • 90
  • The problem is I want to address bad input from the user. For example, if the user typed 1.25ab.0, I don't want to take the 1.25 part and ignore the rest. I guess i could test for more information in the buffer, but that seems like I am leaving an opening for a bug. –  Oct 07 '11 at 22:48