6

所以我目前正在学习 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
}

编辑:我不得不说我刚刚开始并且对您的代码没有丝毫线索,但我会检查您的链接。顺便说一句,我还没有学会如何使用模板,我正在学习如何处理数据,只有我的 C++ Primer Plus 5th edition 的第 3 章。

4

5 回答 5

12

安全的 C++ 方式

您可以使用以下方法为此定义一个函数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());
}

为了帮助您弄清楚它的作用(简化了一些要点):

  • 创建使用给定字符串初始化的输入字符串流
  • 使用operator>>. 这意味着跳过空格并尝试读取双精度。
  • 如果无法读取双精度,则在abc流中设置失败位。请注意,类似的情况3abc会成功并且不会设置失败位。
  • 如果设置了失败位,则ss计算为零值,这意味着false
  • 如果读取了双精度数,我们会跳过尾随空格。如果我们然后在流的末尾(请注意,如果我们尝试读取结束,将eof()返回truestd::ws 。确实如此),eof将返回 true。请注意,此检查确保3abc不会通过我们的检查。
  • 如果两种情况,左右两边的&&求值都为true,我们将 true 返回给调用者,表明给定的字符串是一个双精度字符串。

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

C方式一

这种方式有优点(速度快)但也有主要缺点(不能使用模板概括,需要使用原始指针):

#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将设置endptr为处理的最后一个字符。在我们的例子中是终止空字符。如果未执行转换,则 endptr 设置为给定的字符串的值strtod

C方式二

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

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

结论

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

于 2008-12-02T02:43:44.170 回答
7

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

#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;
}
于 2008-12-02T03:00:55.897 回答
1

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

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

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

于 2008-12-02T03:09:26.253 回答
0

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

于 2008-12-02T02:49:41.770 回答
0

您可以退回到 C 并使用strtod

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

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;
    }
}
于 2008-12-02T02:51:28.910 回答