Как преобразовать число в строку и наоборот в C ++

120

Поскольку этот вопрос задают каждую неделю, этот FAQ может помочь многим пользователям.

  • Как преобразовать целое число в строку в C ++

  • как преобразовать строку в целое число в C ++

  • как преобразовать число с плавающей запятой в строку в C ++

  • как преобразовать строку в число с плавающей запятой в C ++

Армен Цирунян
источник
Для подобного преобразования у меня есть закладка converttypes.com
Фирзок Надим,

Ответы:

129

Обновление для C ++ 11

Как C++11правило, преобразование строки в число и наоборот встроено в стандартную библиотеку. Все следующие функции присутствуют в <string>(согласно параграфу 21.5).

строка в число

float              stof(const string& str, size_t *idx = 0);
double             stod(const string& str, size_t *idx = 0);
long double        stold(const string& str, size_t *idx = 0);
int                stoi(const string& str, size_t *idx = 0, int base = 10);
long               stol(const string& str, size_t *idx = 0, int base = 10);
unsigned long      stoul(const string& str, size_t *idx = 0, int base = 10);
long long          stoll(const string& str, size_t *idx = 0, int base = 10);
unsigned long long stoull(const string& str, size_t *idx = 0, int base = 10);

Каждый из них принимает на вход строку и пытается преобразовать ее в число. Если не удалось создать допустимое число, например, из-за отсутствия числовых данных или из-за того, что число выходит за пределы диапазона для типа, создается исключение ( std::invalid_argumentили std::out_of_range).

Если преобразование прошло успешно, но idxне было 0, idxбудет содержаться индекс первого символа, который не использовался для декодирования. Это может быть индекс за последним символом.

Наконец, целочисленные типы позволяют указать основание, для цифр больше 9 предполагается алфавит ( a=10до z=35). Вы можете найти дополнительную информацию о точном форматировании, которое можно проанализировать здесь для чисел с плавающей запятой , целых чисел со знаком и целых чисел без знака .

Наконец, для каждой функции есть перегрузка, которая принимает в std::wstringкачестве первого параметра.

числовой в строку

string to_string(int val);
string to_string(unsigned val);
string to_string(long val);
string to_string(unsigned long val);
string to_string(long long val);
string to_string(unsigned long long val);
string to_string(float val);
string to_string(double val);
string to_string(long double val);

Это более просто: вы передаете соответствующий числовой тип и получаете обратно строку. Для параметров форматирования вам следует вернуться к параметру stringsream C ++ 03 и использовать манипуляторы потоков, как описано в другом ответе здесь.

Как отмечено в комментариях, эти функции возвращаются к точности мантиссы по умолчанию, которая, вероятно, не является максимальной точностью. Если для вашего приложения требуется более высокая точность, также лучше вернуться к другим процедурам форматирования строк.

Также определены похожие функции с именами to_wstring, они возвращают std::wstring.

KillianDS
источник
3
std::to_stringтеряет большую точность для типов с плавающей запятой. Например, double f = 23.4323897462387526; std::string f_str = std::to_string(f);возвращает строку 23,432390. Это делает невозможным получение значений с плавающей запятой в оба конца с помощью этих функций.
fun4jimmy
@ fun4jimmy - это ограничение, наложенное стандартом или конкретной реализацией? Добавлю к ответу. Не то, чтобы плавание по струнам туда и обратно было хорошей идеей.
KillianDS
Стандарт C ++ гласит: « Возвращает: каждая функция возвращает строковый объект, содержащий символьное представление значения своего аргумента, которое будет сгенерировано при вызове sprintf(buf, fmt, val)со спецификатором формата «% d » , «% u » , «% ld » , » % lu " , "% lld " , "% llu " , "% f " , "% f " или "% Lf " соответственно, где bufобозначает внутренний символьный буфер достаточного размера. "Я взглянул на стандарт C99 для printf и думаю, что количество десятичных знаков зависит от #define DECIMAL_DIGinfloat.h .
fun4jimmy
У Брюса Доусона в своем блоге есть несколько хороших статей о том, какая точность необходима для округления чисел с плавающей запятой .
fun4jimmy
2
На все эти функции влияет глобальный языковой стандарт, что может привести к проблемам при использовании библиотек, особенно при использовании потоков. См. Мой вопрос здесь: stackoverflow.com/questions/31977457/…
Идентификатор
87

Как преобразовать число в строку в C ++ 03

  1. Не следует использовать туitoaилиitofфункциюпотому что они являются нестандартными и поэтому непереносимыми.
  2. Использовать строковые потоки

     #include <sstream>  //include this to use string streams
     #include <string> 
    
    int main()
    {    
        int number = 1234;
    
        std::ostringstream ostr; //output string stream
        ostr << number; //use the string stream just like cout,
        //except the stream prints not to stdout but to a string.
    
        std::string theNumberString = ostr.str(); //the str() function of the stream 
        //returns the string.
    
        //now  theNumberString is "1234"  
    }

    Обратите внимание, что вы можете использовать строковые потоки также для преобразования чисел с плавающей запятой в строку, а также для форматирования строки по своему усмотрению, как и с cout

    std::ostringstream ostr;
    float f = 1.2;
    int i = 3;
    ostr << f << " + " i << " = " << f + i;   
    std::string s = ostr.str();
    //now s is "1.2 + 3 = 4.2" 

    Вы можете использовать манипуляторы потоков, такие как std::endl, std::hexи функции std::setw()и std::setprecision()т. Д., Со строковыми потоками точно так же, как сcout

    Не путайте std::ostringstream сstd::ostrstream. Последний не рекомендуется

  3. Используйте усиление лексики . Если вы не знакомы с ускорением, рекомендуется начать с небольшой библиотеки, такой как lexical_cast. Чтобы загрузить и установить boost и документацию к нему, перейдите сюда . Хотя boost не входит в стандарт C ++, многие библиотеки boost со временем стандартизируются, и boost широко считается одной из лучших библиотек C ++.

    Лексическое приведение использует потоки внизу, поэтому в основном этот вариант такой же, как и предыдущий, только менее подробный.

    #include <boost/lexical_cast.hpp>
    #include <string>
    
    int main()
    {
       float f = 1.2;
       int i = 42;
       std::string sf = boost::lexical_cast<std::string>(f); //sf is "1.2"
       std::string si = boost::lexical_cast<std::string>(i); //sf is "42"
    }

Как преобразовать строку в число в C ++ 03

  1. Самый легкий вариант, унаследованный от C, - это функции atoi(для целых чисел (от алфавита до целого)) и atof(для значений с плавающей запятой (от алфавита до числа с плавающей запятой)). Эти функции принимают строку в стиле C в качестве аргумента ( const char *), и поэтому их использование может считаться не совсем хорошей практикой C ++. На cplusplus.com есть легкая для понимания документация как по atoi, так и по atof, включая то, как они ведут себя в случае неправильного ввода. Однако ссылка содержит ошибку, согласно которой, согласно стандарту, если входное число слишком велико, чтобы соответствовать целевому типу, поведение не определено.

    #include <cstdlib> //the standard C library header
    #include <string>
    int main()
    {
        std::string si = "12";
        std::string sf = "1.2";
        int i = atoi(si.c_str()); //the c_str() function "converts" 
        double f = atof(sf.c_str()); //std::string to const char*
    }
  2. Используйте строковые потоки (на этот раз входной строковый поток istringstream). Опять же, istringstream используется точно так же, как cin. Опять же, не путайте istringstreamс istrstream. Последний не рекомендуется.

    #include <sstream>
    #include <string>
    int main()
    {
       std::string inputString = "1234 12.3 44";
       std::istringstream istr(inputString);
       int i1, i2;
       float f;
       istr >> i1 >> f >> i2;
       //i1 is 1234, f is 12.3, i2 is 44  
    }
  3. Используйте усиление лексики .

    #include <boost/lexical_cast.hpp>
    #include <string>
    
    int main()
    {
       std::string sf = "42.2"; 
       std::string si = "42";
       float f = boost::lexical_cast<float>(sf); //f is 42.2
       int i = boost::lexical_cast<int>(si);  //i is 42
    }       

    В случае неправильного ввода lexical_castвыдает исключение типаboost::bad_lexical_cast

Армен Цирунян
источник
4
Документация cplusplus для atoiне превосходна, это неверно. Не упоминается, что если числовое значение строки не может быть представлено в int, то поведение не определено. Вместо этого он говорит, что значения, выходящие за пределы допустимого диапазона, фиксируются до INT_MAX/ INT_MIN, чего я не могу найти ни в C ++ 03, ни в C89. Для ненадежных / непроверенных входных данных или при работе с базами, которые потоки не поддерживают, вам нужно strtol, что определило поведение ошибки. И аналогичные комментарии для atof/ strtod.
Стив Джессоп,
2
cplusplus.com ошибается насчет "atoi". В нем говорится о возвращаемом значении: «Если действительное преобразование не может быть выполнено, возвращается нулевое значение. Если правильное значение выходит за пределы диапазона представимых значений, возвращается INT_MAX или INT_MIN.», Но в спецификации говорится, что «Если значение результата невозможно представить, поведение не определено ». и что «За исключением поведения при ошибке, они эквивалентны (int)strtol(nptr, (char **)NULL, 10). Функции atoi [...] возвращают преобразованное значение.». cplusplus.com известен как невероятно плохой источник информации для новичков.
Йоханнес Шауб - лит
istr >> i1 >> f >> i2;сильно пропускает проверку на успех.
sbi
4
std::to_string
Могу
1
@ArmenTsirunyan: +10 с моей стороны, один из лучших ответов, которые я когда-либо видел слишком подробно. Спасибо за Ваш ответ.
Abhineet
4

В C ++ 17 новые функции std :: to_chars и std :: from_chars представлены в заголовке charconv .

std :: to_chars не зависит от локали, не выделяет и не бросает.

Предоставляется только небольшой набор политик форматирования, используемых другими библиотеками (такими как std :: sprintf).

Из std :: to_chars , то же самое для std :: from_chars .

Гарантия того, что std :: from_chars может восстановить каждое значение с плавающей запятой, отформатированное to_chars, предоставляется только в том случае, если обе функции принадлежат одной реализации

 // See en.cppreference.com for more information, including format control.
#include <cstdio>
#include <cstddef>
#include <cstdlib>
#include <cassert>
#include <charconv>

using Type =  /* Any fundamental type */ ;
std::size_t buffer_size = /* ... */ ;

[[noreturn]] void report_and_exit(int ret, const char *output) noexcept 
{
    std::printf("%s\n", output);
    std::exit(ret);
}
void check(const std::errc &ec) noexcept
{
    if (ec ==  std::errc::value_too_large)
        report_and_exit(1, "Failed");
}
int main() {
    char buffer[buffer_size];        
    Type val_to_be_converted, result_of_converted_back;

    auto result1 = std::to_chars(buffer, buffer + buffer_size,  val_to_be_converted);
    check(result1.ec);
    *result1.ptr = '\0';

    auto result2 = std::from_chars(buffer, result1.ptr, result_of_converted_back);
    check(result2.ec);

    assert(val_to_be_converted == result_of_converted_back);
    report_and_exit(0, buffer);
}

Хотя это не полностью реализовано компиляторами, оно обязательно будет реализовано.

ЦзяХао Сюй
источник
0

Я украл этот удобный класс откуда-то здесь, в StackOverflow, чтобы преобразовать все, что можно потоково, в строку:

// make_string
class make_string {
public:
  template <typename T>
  make_string& operator<<( T const & val ) {
    buffer_ << val;
    return *this;
  }
  operator std::string() const {
    return buffer_.str();
  }
private:
  std::ostringstream buffer_;
};

И затем вы используете его как;

string str = make_string() << 6 << 8 << "hello";

Отлично!

Также я использую эту функцию для преобразования строк во что-либо потоковое, хотя это не очень безопасно, если вы попытаетесь проанализировать строку, не содержащую числа; (и не такой умный, как предыдущий)

// parse_string
template <typename RETURN_TYPE, typename STRING_TYPE>
RETURN_TYPE parse_string(const STRING_TYPE& str) {
  std::stringstream buf;
  buf << str;
  RETURN_TYPE val;
  buf >> val;
  return val;
}

Использовать как:

int x = parse_string<int>("78");

Вам также могут понадобиться версии для wstrings.

Виктор Зер
источник
5
Именно это и делает boost :: lexical_cast. И boost делает это в более общем плане.
Армен Цирунян
Правда, я бегло просмотрел первый ответ и не увидел boost :: lexical_casts.
Виктор Сер