Проверьте тип переменной в C ++ - PullRequest
6 голосов
/ 02 декабря 2008

Итак, я сейчас изучаю 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
}

Редактировать: Я бы сказал, что только что начал и не имею ни малейшего понятия о вашем коде, но я проверю вашу ссылку. Кстати, я еще не научился работать с шаблонами, я учусь работать с данными, только глава 3 в моем C ++ Primer Plus 5-е издание.

Ответы [ 5 ]

12 голосов
/ 02 декабря 2008

Safe C ++ Way

Вы можете определить функцию для этого, используя 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>>. Это означает пропуск пробела и попытку прочитать двойное число.
  • Если не может быть прочитано значение типа double, как в abc, поток устанавливает fail -бит. Обратите внимание, что такие случаи, как 3abc будут успешными и не установит бит ошибки.
  • Если бит сбоя установлен, ss оценивается как нулевое значение, что означает false .
  • Если был прочитан двойной код, мы пропускаем завершающий пробел. Если мы затем окажемся в конце потока (обратите внимание, что eof() вернет true , если мы попытались прочитать после конца. std::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 Way One

Этот способ имеет преимущества (быстрота), но также и серьезные недостатки (не может быть обобщен при использовании шаблона, необходимо работать с необработанными указателями):

#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 Way Two

Возможно, что 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 ++.

7 голосов
/ 02 декабря 2008

Нет подходящего способа проверить, содержит ли строка действительно двойное значение в стандартной библиотеке. Вы, вероятно, хотите использовать Boost . Следующее решение основано на рецепте 3.3 в 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;
}
1 голос
/ 02 декабря 2008

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.

0 голосов
/ 02 декабря 2008

Вы можете использовать C и использовать strtod

Вы программируете чтение в строке и затем передаете ее функции, которая пытается преобразовать строку в 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;
    }
}
0 голосов
/ 02 декабря 2008

Я бы сказал, что только начал и не имею ни малейшего понятия о вашем коде, но я проверю вашу ссылку. Кстати, я еще не научился работать с шаблонами, я учусь работать с данными, только глава 3 в моем C ++ Primer Plus 5-е издание.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...