Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check variable type in C++

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.

like image 420
Fatmarik Avatar asked Dec 02 '08 02:12

Fatmarik


1 Answers

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++.

like image 176
Johannes Schaub - litb Avatar answered Oct 05 '22 18:10

Johannes Schaub - litb