Як перетворити число в рядок і навпаки в C ++


120

Оскільки це запитання задається щотижня, цей FAQ може допомогти багатьом користувачам.

  • Як перетворити ціле число в рядок в C ++

  • як перетворити рядок у ціле число в C ++

  • як перетворити число з плаваючою комою в рядок у C ++

  • як перетворити рядок у число з плаваючою комою в C ++


Для такої конверсії у мене є закладка converttypes.com
Firzok Nadeem

Відповіді:


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). Ви можете знайти більше інформації про точне форматування, яке можна проаналізувати тут для чисел з плаваючою комою , підписаних цілих чисел та непідписаних цілих чисел .

Нарешті, для кожної функції також існує перевантаження, яка приймає a 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);

Вони більш прості, ви передаєте відповідний числовий тип і отримуєте рядок назад. Для параметрів форматування слід повернутися до параметра струнного потоку C ++ 03 і використовувати маніпулятори потоку, як пояснено в іншій відповіді тут.

Як зазначається в коментарях, ці функції повертаються до точності мантіси за замовчуванням, що, ймовірно, не є максимальною точністю. Якщо для вашої програми потрібна більша точність, також краще повернутися до інших процедур форматування рядків.

Також визначені подібні функції, які названі to_wstring, вони повернуть a std::wstring.


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_DIGдюймаfloat.h .
fun4jimmy

Брюс Доусон має кілька хороших статей про те, яка точність потрібна для круглих відключень чисел з плаваючою комою у своєму блозі .
fun4jimmy

2
На всі ці функції впливає глобальна локаль, що може призвести до проблем, якщо ви використовуєте бібліотеки, а особливо, якщо використовуєте потоки. Дивіться моє запитання тут: stackoverflow.com/questions/31977457/…
Повідомлення

86

Як перетворити число в рядок в 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. Щоб завантажити та встановити бустер та його документацію, перейдіть сюди . Хоча прискорення не в стандарті C ++, багато бібліотек прискорення з часом стандартизуються, і прискорення вважається кращими бібліотеками 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
Pubby

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. І прискорення робить це в більш загальній формі.
Армен Цирунян

Правда, я переглянув першу відповідь і не побачив прискорення :: lexical_casts.
Віктор Шер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.