在 C++ 中检查变量类型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/332852/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:42:42  来源:igfitidea点击:

Check variable type in C++

c++variablesdouble

提问by Fatmarik

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:

所以我目前正在学习 C++ 并决定制作一个程序来测试我迄今为止所学的技能。现在在我的代码中,我想检查用户输入的值是否是双精度值,如果不是双精度值,我将放置一个 if 循环并要求他们重新输入它。我遇到的问题是如何检查用户输入的变量类型,例如,如果用户输入字符或字符串,我可以输出错误消息。这是我的代码:

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

编辑:我不得不说我刚刚开始,对你的代码一无所知,但我会查看你的链接。顺便说一句,我还没有学会如何使用模板,我正在学习处理数据,只在我的 C++ Primer Plus 5th edition 中的第 3 章。

回答by Johannes Schaub - litb

Safe C++ Way

安全的 C++ 方式

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

您可以使用以下方法为此定义一个函数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 abcthe stream sets the fail-bit. Note that cases like 3abcwill succeed and will notset the fail-bit.
  • If the fail-bit is set, ssevaluates 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 trueif we tried to read past the end. std::wsdoes exactly that), eofwill return true. Note this check makes sure that 3abcwill 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.
  • 创建使用给定字符串初始化的输入字符串流
  • 使用operator>>. 这意味着跳过空格并尝试读取双精度值。
  • 如果无法读取双精度值,则在abc流中设置失败位。请注意,像这样的情况3abc会成功并且不会设置失败位。
  • 如果设置了失败位,则ss计算为零值,这意味着false
  • 如果读取了双精度值,我们将跳过尾随空格。然后如果我们是在流结束(注意,eof()将返回,如果我们试图读取过去的结束。std::ws正是这么做的),eof将返回true。请注意,此检查确保3abc不会通过我们的检查。
  • 如果两种情况,左右两边的&&求值为true,我们将 true 返回给调用者,表示给定的字符串是双精度值。

Similar, you check for intand 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_castprovides to you. Check it out: http://www.boost.org/doc/libs/1_37_0/libs/conversion/lexical_cast.htm.

类似地,您检查int和其他类型。如果您知道如何使用模板,那么您也知道如何将其推广到其他类型。顺便说一句,这正是boost::lexical_cast为您提供的。检查一下:http: //www.boost.org/doc/libs/1_37_0/libs/conversion/lexical_cast.htm

C Way One

C方式一

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 == '
#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()));
}
'); }

strtodwill set endptrto 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.

strtod将设置endptr为处理的最后一个字符。在我们的例子中是终止空字符。如果未执行任何转换,则 endptr 设置为提供给 的字符串值strtod

C Way Two

C 方式二

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

一件事可以解决std::sscanf问题。但监督某事很容易。这是正确的方法:

#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;
}

std::sscanfwill return the items converted. Although the Standard specifies that %nis 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). nwill 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.

std::sscanf将返回转换后的项目。尽管该标准规定%n不包括在该计数中,但有几个来源相互矛盾。最好进行比较>=以使其正确(请参阅 的联机帮助页sscanf)。n将设置为已处理字符的数量。它与字符串的大小进行比较。两个格式说明符之间的空格是可选的尾随空格。

Conclusion

结论

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

如果您是初学者,请阅读std::stringstream并按照 C++ 方式进行操作。最好不要乱用指针,直到您对 C++ 的一般概念感到满意为止。

回答by Federico A. Ramponi

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

在标准库中没有合适的方法来检查字符串是否真的包含双精度值。您可能想使用Boost。以下解决方案的灵感来自C++ Cookbook 中的配方 3.3 :

//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
}

回答by strager

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

sscanf可以为所欲为;它返回正确处理的参数数量。这应该让你开始:

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;
    }
}

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

其他答案中发布的其他方法各有优缺点。这个有尾随字符问题,不是“C++”-y。

回答by Fatmarik

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.

我不得不说我刚刚开始,对你的代码一无所知,但我会查看你的链接。顺便说一句,我还没有学会如何使用模板,我正在学习处理数据,只在我的 C++ Primer Plus 5th edition 中的第 3 章。

回答by maccullt

You can fall back on C and use strtod

您可以使用 C 并使用strtod

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

您的程序读入一个字符串,然后将其传递给一个尝试将该字符串转换为双精度的函数。

##代码##