Question

So I am currently learning C++ and decided to make a program that tests my skills I have learned so far. Now in my code I want to check if the value that the user enters is a double, if it is not a double I will put a if loop and ask them to reenter it. The problem I have is how do I go about checking what type of variable the user enters, ex- if a user enters a char or string, I can output an error message. Here is my code:

//cubes a user entered number
#include <iostream>
using namespace std;

double cube(double n); //function prototype

int main()
{
    cout << "Enter the number you want to cube: "; //ask user to input number
    double user;
    cin >> user;  //user entering the number

    cout << "The cube of " << user << " is " << cube(user) << "." << endl; //displaying the cubed number

    return 0;
}

double cube (double n) //function that cubes the number
{
    return n*n*n; // cubing the number and returning it
}

Edit: I would have to say I just started and don't have the slightest of clue about your code, but I will check out your link. By the way, I haven't learned how to work with templates yet,I am learning about dealing with data, only Chapter 3 in my C++ Primer Plus 5th edition.

Was it helpful?

Solution

There is no suitable way to check if a string really contains a double within the standard library. You probably want to use Boost. The following solution is inspired by recipe 3.3 in C++ Cookbook:

#include <iostream>
#include <boost/lexical_cast.hpp>
using namespace std;
using namespace boost;

double cube(double n);

int main()
{
    while(true)
    {
        cout << "Enter the number you want to cube: ";
        string user;
        cin >> user;

        try
        {
            // The following instruction tries to parse a double from the 'user' string.
            // If the parsing fails, it raises an exception of type bad_lexical_cast.
            // If an exception is raised within a try{ } block, the execution proceeds
            // with one of the following catch() blocks
            double d = lexical_cast <double> (user);   

            cout << "The cube of " << d << " is " << cube(d) << "." << endl;
            break;
        }
        catch(bad_lexical_cast &e)
        {
            // This code is executed if the lexical_cast raised an exception; We
            // put an error message and continue with the loop
            cout << "The inserted string was not a valid double!" << endl;
        }
    }
    return 0;
}

double cube (double n)
{
    return n*n*n;
}

OTHER TIPS

Safe C++ Way

You can define a function for this using std::istringstream:

#include <sstream>  

bool is_double(std::string const& str) {
    std::istringstream ss(str);

    // always keep the scope of variables as close as possible. we see
    // 'd' only within the following block.
    {
        double d;
        ss >> d;
    }

    /* eat up trailing whitespace if there was a double read, and ensure
     * there is no character left. the eof bit is set in the case that
     * `std::ws` tried to read beyond the stream. */
    return (ss && (ss >> std::ws).eof());
}

To assist you in figuring out what it does (some points are simplified):

  • Creation of a input-stringstream initialized with the string given
  • Reading a double value out of it using operator>>. This means skipping whitespace and trying to read a double.
  • If no double could be read, as in abc the stream sets the fail-bit. Note that cases like 3abc will succeed and will not set the fail-bit.
  • If the fail-bit is set, ss evaluates to a zero value, which means false.
  • If an double was read, we skip trailing whitespace. If we then are at the end of the stream (note that eof() will return true if we tried to read past the end. std::ws does exactly that), eof will return true. Note this check makes sure that 3abc will not pass our check.
  • If both cases, right and left of the && evaluate to true, we return true to the caller, signaling the given string is a double.

Similar, you check for int and other types. If you know how to work with templates, you know how to generalize this for other types as well. Incidentally, this is exactly what boost::lexical_cast provides to you. Check it out: http://www.boost.org/doc/libs/1_37_0/libs/conversion/lexical_cast.htm.

C Way One

This way has advantages (being fast) but also major disadvantages (can't generalized using a template, need to work with raw pointers):

#include <cstdlib>
#include <cctype>  

bool is_double(std::string const& s) {
    char * endptr;
    std::strtod(s.c_str(), &endptr);
    if(endptr != s.c_str()) // skip trailing whitespace
        while(std::isspace(*endptr)) endptr++;
    return (endptr != s.c_str() && *endptr == '\0');
}

strtod will set endptr to the last character processed. Which is in our case the terminating null character. If no conversion was performed, endptr is set to the value of the string given to strtod.

C Way Two

One might thing that std::sscanf does the trick. But it's easy to oversee something. Here is the correct way to do it:

#include <cstdio>

bool is_double(std::string const& s) {
    int n;
    double d;
    return (std::sscanf(s.c_str(), "%lf %n", &d, &n) >= 1 && 
            n == static_cast<int>(s.size()));
}

std::sscanf will return the items converted. Although the Standard specifies that %n is not included in that count, several sources contradict each other. It's the best to compare >= to get it right (see the manpage of sscanf). n will be set to the amount of the processed characters. It is compared to the size of the string. The space between the two format specifiers accounts for optional trailing whitespace.

Conclusion

If you are a beginner, read into std::stringstream and do it the C++ way. Best not mess with pointers until you feel good with the general concept of C++.

sscanf can do what you want; it returns the number of arguments properly processed. This should get you started:

//cubes a user entered number
#include <iostream>
#include <cstdio>
using namespace std;

double cube(double n); //function prototype

int main()
{
        cout << "Enter the number you want to cube: "; //ask user to input number
        string user;
        cin >> user;  //user entering the number

        // Convert the number to a double.
        double value;
        if(sscanf(user.c_str(), "%lf", &value) != 1)
        {
                cout << "Bad!  " << user << " isn't a number!" << endl;
                return 1;
        }

        cout << "The cube of " << user << " is " << cube(user) << "." << endl; //displaying the cubed number

        return 0;
}

double cube (double n) //function that cubes the number
{
        return n*n*n; // cubing the number and returning it
}

Other methods posted in other answers have their advantages and disadvantages. This one has issues with trailing characters and isn't "C++"-y.

I would have to say I just started and don't have the slightest of clue about your code, but I will check out your link. By the way, I haven't learned how to work with templates yet,I am learning about dealing with data, only Chapter 3 in my C++ Primer Plus 5th edition.

You can fall back on C and use strtod

You program reads in a string and then passes it to a function that attempts to convert the string into double.

bool is_double(const char* strIn, double& dblOut) {
    char* lastConvert = NULL;
    double d = strtod(strIn, &lastConvert);
    if(lastConvert == strIn){
        return false;
    } else {
       dblOut = d;
       return true;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top