C ++ 'da bir sayıyı dizeye dönüştürme ve bunun tersi


120

Bu soru her hafta sorulduğundan, bu SSS birçok kullanıcıya yardımcı olabilir.

  • C ++ 'da bir tamsayıyı dizeye dönüştürme

  • C ++ 'da bir dizeyi tam sayıya dönüştürme

  • kayan noktalı bir sayıyı C ++ 'da dizeye dönüştürme

  • C ++ 'da bir dizeyi kayan noktalı sayıya dönüştürme


Bunun gibi dönüşümler için bir yer
imim

Yanıtlar:


129

C ++ 11 güncellemesi

İtibarıyla C++11, standart, dize kadar-numarası dönüştürülmesi veya bunun tam tersi, standart kütüphaneye inşa edilir. Aşağıdaki tüm işlevler <string>(21.5 paragrafına göre) içinde mevcuttur.

sayısal dizge

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

Bunların her biri girdi olarak bir dizge alır ve onu bir sayıya dönüştürmeye çalışır. Örneğin sayısal veri olmadığından veya sayı tür için aralık dışı olduğundan geçerli bir sayı oluşturulamazsa, bir istisna atılır ( std::invalid_argumentveya std::out_of_range).

Dönüştürme başarılıysa ve başarılı idxdeğilse 0, idxkod çözme için kullanılmayan ilk karakterin dizinini içerecektir. Bu, son karakterin arkasındaki bir dizin olabilir.

Son olarak, integral türleri bir taban belirtmeye izin verir, 9'dan büyük basamaklar için alfabenin ( a=10kadar z=35) olduğu varsayılır . Kayan nokta sayıları , işaretli tam sayılar ve işaretsiz tam sayılar için burada ayrıştırılabilecek tam biçimlendirme hakkında daha fazla bilgi bulabilirsiniz .

Son olarak, her işlev için, a'yı std::wstringbirinci parametre olarak kabul eden bir aşırı yük vardır .

dizeye sayısal

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

Bunlar daha basittir, uygun sayısal türü iletirsiniz ve bir dizi geri alırsınız. Biçimlendirme seçenekleri için, burada başka bir cevapta açıklandığı gibi, C ++ 03 dizgi akışı seçeneğine geri dönmeli ve akış manipülatörlerini kullanmalısınız.

Yorumlarda belirtildiği gibi, bu işlevler, büyük olasılıkla maksimum kesinlik olmayan varsayılan bir mantis hassasiyetine geri döner. Uygulamanız için daha fazla hassasiyet gerekiyorsa, diğer dize biçimlendirme prosedürlerine geri dönmeniz en iyisidir.

Ayrıca adlandırılmış tanımlanmış benzer işlevler de vardır to_wstring, bunlar bir std::wstring.


3
std::to_stringkayan nokta türleri için çok fazla hassasiyet kaybeder. Örneğin double f = 23.4323897462387526; std::string f_str = std::to_string(f);23.432390 dize döndürür. Bu, bu işlevleri kullanarak kayan noktalı değerlerin döndürülmesini imkansız kılar.
fun4jimmy

@ fun4jimmy bu, standart veya uygulamaya özgü bir kısıtlama mıdır? Cevaba ekleyecektir. İpler arasında gidip gelme hiç iyi bir fikir değil.
KillianDS

C ++ standart "diyor İade: Her işlev çağırarak yaratacağı onun argüman değerinin karakter temsilini tutan bir dize nesnesi döndüren sprintf(buf, fmt, val)bir biçim belirteci ile '' % d , '' % u , '% ld' , " % lu " , "% lld " , "% llu " , "% f " , "% f " veya "% Lf " , burada bufyeterli büyüklükte bir dahili karakter arabelleğini belirtir. "Ben bir göz vardı C99 standardı printf ve ondalık basamak sayısı bağlı olduğunu düşünüyorum #define DECIMAL_DIGiçindefloat.h .
fun4jimmy

Bruce Dawson'ın blogunda , kayan noktalı sayıları gidiş geliş için hangi hassasiyetin gerekli olduğuna dair bazı iyi makaleler var .
fun4jimmy

2
Tüm bu işlevler küresel yerel ayardan etkilenir ve bu da kitaplıkları kullanırsanız ve özellikle evreler kullanıyorsanız sorunlara yol açabilir. Soruma buradan bakın: stackoverflow.com/questions/31977457/…
kimlik

87

C ++ 03'te bir sayıyı dizeye dönüştürme

  1. Kullanmayınitoa veyaitofonlar standart dışı ve dolayısıyla taşınabilir değildir çünkü fonksiyonları.
  2. Dize akışlarını kullanın

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

    Dize akışlarını, kayan noktalı sayıları dizeye dönüştürmek ve ayrıca dizeyi istediğiniz gibi biçimlendirmek için de kullanabileceğinizi unutmayın. 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::hexVe işlevleri std::setw(), std::setprecision()vb. Gibi akış manipülatörlerini, dizgi akışlarıyla tam olarak aynı şekilde kullanabilirsiniz.cout

    Karıştırmayın std::ostringstream ilestd::ostrstream. İkincisi kullanımdan kaldırıldı

  3. Kullanım sözcük döküm artırmak . Eğer boost'a aşina değilseniz, bu lexical_cast gibi küçük bir kitaplıkla başlamak iyi bir fikirdir. Boost ve belgelerini indirmek ve yüklemek için buraya gidin . Güçlendirme C ++ standardında olmasa da, birçok destek kitaplığı sonunda standartlaştırılır ve yükseltme, en iyi C ++ kitaplıkları arasında yaygın olarak kabul edilir.

    Sözcüksel döküm, altındaki akışları kullanır, bu nedenle temelde bu seçenek öncekiyle aynıdır, sadece daha az ayrıntılıdır.

    #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'te bir dizeyi sayıya dönüştürme

  1. C'den miras alınan en hafif seçenek, işlevlerdir atoi(tamsayılar için (alfabetikten tamsayıya)) ve atof(kayan nokta değerleri için (alfabetikten kayan değere)). Bu işlevler, argüman ( const char *) olarak C tarzı bir dizge alır ve bu nedenle kullanımları tam olarak iyi olmayan bir C ++ uygulaması olarak kabul edilebilir . cplusplus.com hem belgelerine anlaşılması kolay sahiptir atoi ve atof onlar kötü girdi durumunda nasıl davrandıkları dahil. Bununla birlikte, bağlantı, standarda göre, giriş sayısı hedef tipine sığamayacak kadar büyükse, davranış tanımsız olduğundan bir hata içerir.

    #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. Dize akışlarını kullanın (bu sefer giriş dizesi akışı istringstream). Yine istringstream aynı cin. Yine, karıştırmayın istringstreamile istrstream. İkincisi kullanımdan kaldırılmıştır.

    #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. Kullanım sözcük döküm artırmak .

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

    Hatalı bir girdi durumunda, bir lexical_casttür istisnası atarboost::bad_lexical_cast


4
Cplusplus belgeleri atoimükemmel değil, yanlış. Dizenin sayısal değeri içinde intgösterilemezse davranışın tanımsız olduğunu belirtmez . Bunun yerine, aralık dışı değerlerin C ++ 03 veya C89'da bulamadığım INT_MAX/ olarak sabitlendiğini söylüyor INT_MIN. Güvenilmeyen / doğrulanmamış girdiler için veya akışların desteklemediği tabanlarla uğraşırken strtol, tanımlanmış hata davranışına sahip olmanız gerekir . Ve atof/ için benzer yorumlar strtod.
Steve Jessop

2
cplusplus.com "atoi" hakkında yanılıyor. Dönüş değeri hakkında "Geçerli bir dönüştürme yapılamazsa, sıfır değeri döndürülür. Doğru değer gösterilebilir değerler aralığının dışındaysa, INT_MAX veya INT_MIN döndürülür." Diyor, ancak özellik "If the sonucun değeri gösterilemez, davranış tanımlanmamıştır. " ve "Hatalı davranış dışında, eşdeğerdirler (int)strtol(nptr, (char **)NULL, 10). atoi [...] işlevleri dönüştürülen değeri döndürür." cplusplus.com, yeni başlayanlar için inanılmaz kötü bir bilgi kaynağı olarak bilinir.
Johannes Schaub -

istr >> i1 >> f >> i2;başarı kontrolünü fena halde kaçırır.
sbi

4
Eklemek isteyebilirsinizstd::to_string
Pubby

1
@ArmenTsirunyan: Benim tarafımdan +10, Bunu da derinlemesine gördüğüm en iyi cevaplardan biri. Cevabınız için teşekkürler.
Abhineet

4

C ++ 17'de, yeni işlevler std :: to_chars ve std :: from_chars , charconv başlığında tanıtıldı .

std :: to_chars yerel ayardan bağımsızdır, ayırmaz ve atmaz.

Diğer kitaplıklar tarafından kullanılan biçimlendirme ilkelerinin yalnızca küçük bir alt kümesi (std :: sprintf gibi) sağlanır.

Gönderen std :: to_chars , aynı std :: from_chars .

Std :: from_chars'ın to_chars ile biçimlendirilmiş her kayan noktalı değeri tam olarak kurtarabileceği garantisi yalnızca her iki işlev de aynı uygulamadan ise sağlanır.

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

Derleyiciler tarafından tam olarak uygulanmasa da kesinlikle uygulanacaktır.


0

Bu uygun sınıfı, akışkan olan her şeyi bir dizeye dönüştürmek için StackOverflow'da bir yerden çaldım:

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

Ve sonra bunu;

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

Oldukça şık!

Ayrıca bu işlevi dizeleri akışkan olan herhangi bir şeye dönüştürmek için kullanıyorum, ancak sayı içermeyen bir dizgeyi ayrıştırmaya çalışırsanız çok güvenli olmasa da; (ve sonuncusu kadar zeki değil)

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

Kullanım şekli:

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

Ayrıca wstrings için sürümler de isteyebilirsiniz.


5
Bu tam olarak boost :: lexical_cast'in yaptığı şeydir. Ve boost, bunu daha genel bir ortamda yapar.
Armen Tsirunyan

Doğru, ilk cevaba göz attım ve artış :: lexical_casts'i görmedim.
Viktor Sehr
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.