Jak przekonwertować liczbę na ciąg i odwrotnie w C ++

120

Ponieważ to pytanie jest zadawane co tydzień, to FAQ może pomóc wielu użytkownikom.

  • Jak przekonwertować liczbę całkowitą na ciąg w C ++

  • jak przekonwertować ciąg znaków na liczbę całkowitą w C ++

  • jak przekonwertować liczbę zmiennoprzecinkową na ciąg w C ++

  • jak przekonwertować ciąg na liczbę zmiennoprzecinkową w C ++

Armen Tsirunyan
źródło
Do takiej konwersji mam zakładkę converttypes.com
Firzok Nadeem

Odpowiedzi:

129

Aktualizacja dla C ++ 11

Począwszy od C++11standardowego, konwersji i string-to-liczby odwrotnie są wbudowane w bibliotece standardowej. Wszystkie poniższe funkcje są dostępne w <string>(zgodnie z paragrafem 21.5).

ciąg na numeryczny

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

Każdy z nich przyjmuje ciąg znaków jako dane wejściowe i próbuje przekształcić go w liczbę. Jeśli nie można skonstruować prawidłowej liczby, na przykład ponieważ nie ma danych liczbowych lub liczba jest poza zakresem dla typu, zgłaszany jest wyjątek ( std::invalid_argumentlub std::out_of_range).

Jeśli konwersja zakończyła się powodzeniem i idxnie 0, idxbędzie zawierać indeks pierwszego znaku, który nie został użyty do dekodowania. Może to być indeks znajdujący się za ostatnim znakiem.

Wreszcie typy całkowite pozwalają określić podstawę, dla cyfr większych niż 9 zakłada się alfabet ( a=10do z=35). Więcej informacji na temat dokładnego formatowania, które można przeanalizować tutaj dla liczb zmiennoprzecinkowych , liczb całkowitych ze znakiem i liczb całkowitych bez znaku .

Wreszcie, dla każdej funkcji istnieje również przeciążenie, które akceptuje std::wstringjako pierwszy parametr.

numeryczne na ciąg

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

Są prostsze, przekazujesz odpowiedni typ liczbowy i otrzymujesz ciąg znaków z powrotem. W przypadku opcji formatowania należy wrócić do opcji stringsream C ++ 03 i użyć manipulatorów strumienia, jak wyjaśniono w innej odpowiedzi tutaj.

Jak zauważono w komentarzach, funkcje te powracają do domyślnej precyzji mantysy, która prawdopodobnie nie jest maksymalną dokładnością. Jeśli aplikacja wymaga większej precyzji, najlepiej wrócić do innych procedur formatowania ciągów.

Istnieją również zdefiniowane podobne funkcje o nazwach to_wstring, które zwrócą plik std::wstring.

KillianDS
źródło
3
std::to_stringtraci dużo precyzji dla typów zmiennoprzecinkowych. Na przykład double f = 23.4323897462387526; std::string f_str = std::to_string(f);zwraca ciąg 23,432390. Uniemożliwia to zaokrąglanie wartości zmiennoprzecinkowych za pomocą tych funkcji.
fun4jimmy
@ fun4jimmy czy jest to ograniczenie narzucone przez normę lub konkretną implementację? Dodam to do odpowiedzi. Nie to, że okrągłe potknięcia płyną przez struny są dobrym pomysłem.
KillianDS
Standard C ++ mówi: „ Zwraca: Każda funkcja zwraca obiekt typu string zawierający reprezentację znakową wartości jej argumentu, który zostałby wygenerowany przez wywołanie sprintf(buf, fmt, val)ze specyfikatorem formatu „% d ” , „% u ” , „% ld ” , „ % lu " , "% lld " , "% llu " , "% f " , "% f " lub "% Lf " , odpowiednio, gdzie bufoznacza wewnętrzny bufor znaków o wystarczającej wielkości. "Rzuciłem okiem na standard C99 dla printf i myślę, że liczba miejsc dziesiętnych zależy od #define DECIMAL_DIGwfloat.h .
fun4jimmy
Bruce Dawson ma na swoim blogu kilka dobrych artykułów na temat tego, jaka precyzja jest potrzebna do wykonywania okrągłych liczb zmiennoprzecinkowych .
fun4jimmy
2
Globalne ustawienia regionalne mają wpływ na wszystkie te funkcje, co może prowadzić do problemów w przypadku korzystania z bibliotek, a zwłaszcza w przypadku korzystania z wątków. Zobacz moje pytanie tutaj: stackoverflow.com/questions/31977457/ ...
Ident
87

Jak przekonwertować liczbę na ciąg w C ++ 03

  1. Nie stosować naitoalubitoffunkcji, ponieważ są one nietypowe i dlatego nie przenośne.
  2. Użyj strumieni ciągów

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

    Zwróć uwagę, że możesz używać strumieni ciągów również do konwersji liczb zmiennoprzecinkowych na łańcuchy, a także do formatowania łańcucha według własnego uznania, tak jak w przypadku 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" 

    Możesz używać manipulatorów strumieni, takich jak std::endl, std::hexi funkcje std::setw(), std::setprecision()itp. Ze strumieniami łańcuchów w dokładnie taki sam sposób, jak w przypadkucout

    Nie myl std::ostringstream zstd::ostrstream. Ta ostatnia jest przestarzała

  3. Użyj wzmocnienia leksykalnego rzutowania . Jeśli nie jesteś zaznajomiony z boost, dobrym pomysłem jest rozpoczęcie od małej biblioteki, takiej jak ten lexical_cast. Aby pobrać i zainstalować Boost oraz jego dokumentację, przejdź tutaj . Chociaż boost nie jest w standardzie C ++, wiele bibliotek boost zostaje ostatecznie ustandaryzowanych, a boost jest powszechnie uważany za najlepsze biblioteki C ++.

    Obsada leksykalna używa strumieni pod spodem, więc w zasadzie ta opcja jest taka sama jak poprzednia, tylko mniej szczegółowa.

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

Jak przekonwertować ciąg na liczbę w C ++ 03

  1. Najlżejszą opcją, dziedziczoną z C, są funkcje atoi(dla liczb całkowitych (alfabetycznie do liczby całkowitej)) i atof(dla wartości zmiennoprzecinkowych (alfabetycznie do liczby zmiennoprzecinkowej)). Te funkcje przyjmują ciąg znaków w stylu C jako argument ( const char *) i dlatego ich użycie może być uważane za niezbyt dobrą praktykę C ++. cplusplus.com ma łatwą do zrozumienia dokumentację zarówno na temat atoi, jak i atof, w tym jak zachowują się w przypadku złego wejścia. Jednak łącze zawiera błąd polegający na tym, że zgodnie ze standardem, jeśli liczba wejściowa jest zbyt duża, aby zmieścić się w typie docelowym, zachowanie jest niezdefiniowane.

    #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. Użyj strumieni ciągów (tym razem wejściowego strumienia ciągów istringstream). Ponownie, istringstream jest używany tak samo jak cin. Ponownie, nie myl istringstreamz istrstream. Ta ostatnia jest przestarzała.

    #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. Użyj wzmocnienia leksykalnego rzutowania .

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

    W przypadku złego wejścia lexical_castzgłasza wyjątek typuboost::bad_lexical_cast

Armen Tsirunyan
źródło
4
Dokumentacja cplusplus dla atoinie jest doskonała, jest niepoprawna. Nie wspomina, że ​​jeśli wartość liczbowa ciągu nie może być reprezentowana w int, to zachowanie jest niezdefiniowane. Zamiast tego mówi, że wartości spoza zakresu są zaciskane na INT_MAX/ INT_MIN, czego nie mogę znaleźć ani w C ++ 03, ani w C89. W przypadku niezaufanych / niezweryfikowanych danych wejściowych lub w przypadku baz, których strumienie nie obsługują, potrzebujesz strtol, które ma zdefiniowane zachowanie błędów. I podobne komentarze dla atof/ strtod.
Steve Jessop
2
cplusplus.com myli się co do atoi. Mówi o wartości zwracanej „Jeśli nie można było przeprowadzić żadnej prawidłowej konwersji, zwracana jest wartość zerowa. Jeśli prawidłowa wartość jest poza zakresem reprezentowalnych wartości, zwracana jest wartość INT_MAX lub INT_MIN.”, Ale specyfikacja mówi, że „Jeśli wartości wyniku nie można przedstawić, zachowanie jest niezdefiniowane. " i że „Z wyjątkiem zachowania w przypadku błędu, są one równoważne (int)strtol(nptr, (char **)NULL, 10). Funkcje atoi [...] zwracają przekonwertowaną wartość.”. cplusplus.com jest znane jako niesamowite źródło informacji dla początkujących.
Johannes Schaub - litb
istr >> i1 >> f >> i2;bardzo tęskni za czekiem na sukces.
sbi
4
Może chciałbym dodaćstd::to_string
Pubby
1
@ArmenTsirunyan: +10 z mojego końca, jedna z najlepszych odpowiedzi, jakie kiedykolwiek widziałem dogłębnie. Dziękuję za odpowiedź.
Abhineet
4

W C ++ 17 nowe funkcje std :: to_chars i std :: from_chars zostały wprowadzone w nagłówku charconv .

std :: to_chars jest niezależne od ustawień regionalnych, nie przypisuje i nie rzuca.

Udostępniony jest tylko niewielki podzbiór zasad formatowania używanych przez inne biblioteki (na przykład std :: sprintf).

Od std :: to_chars , to samo dla std :: from_chars .

Gwarancja, że ​​std :: from_chars może odzyskać każdą wartość zmiennoprzecinkową sformatowaną dokładnie przez to_chars, jest zapewniana tylko wtedy, gdy obie funkcje pochodzą z tej samej implementacji

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

Chociaż nie jest w pełni zaimplementowany przez kompilatory, na pewno zostanie zaimplementowany.

JiaHao Xu
źródło
0

Ukradłem tę wygodną klasę gdzieś tutaj w StackOverflow, aby przekonwertować wszystko, co można strumieniować na ciąg:

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

A potem używasz go jako;

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

Całkiem fajnie!

Używam również tej funkcji do konwersji łańcuchów znaków na wszystko, co można przesyłać strumieniowo, chociaż nie jest to zbyt bezpieczne, jeśli spróbujesz przeanalizować ciąg niezawierający liczby; (i nie jest tak sprytny jak ostatni)

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

Użyj jako:

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

Możesz także potrzebować wersji dla wstrings.

Viktor Sehr
źródło
5
To jest dokładnie to, co robi boost :: lexical_cast. A boost robi to w bardziej ogólnym stylu.
Armen Tsirunyan
To prawda, przejrzałem pierwszą odpowiedź i nie widziałem wzmocnienia :: lexical_casts.
Viktor Sehr