Come convertire un numero in stringa e viceversa in C ++


120

Poiché questa domanda viene posta ogni settimana, questa FAQ potrebbe aiutare molti utenti.

  • Come convertire un intero in una stringa in C ++

  • come convertire una stringa in un numero intero in C ++

  • come convertire un numero a virgola mobile in una stringa in C ++

  • come convertire una stringa in un numero a virgola mobile in C ++


Per conversioni come queste, ho un segnalibro converttypes.com
Firzok Nadeem

Risposte:


129

Aggiornamento per C ++ 11

A partire dallo C++11standard, la conversione da stringa a numero e viceversa sono incorporate nella libreria standard. Tutte le seguenti funzioni sono presenti in<string> (come da paragrafo 21.5) .

stringa in numerico

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

Ognuno di questi prende una stringa come input e proverà a convertirla in un numero. Se non è stato possibile costruire un numero valido, ad esempio perché non ci sono dati numerici o il numero è fuori intervallo per il tipo, viene generata un'eccezione ( std::invalid_argumentostd::out_of_range ).

Se la conversione è riuscita e idxnon lo è 0,idx conterrà l'indice del primo carattere che non è stato utilizzato per la decodifica. Questo potrebbe essere un indice dietro l'ultimo carattere.

Infine, i tipi integrali consentono di specificare una base, per cifre maggiori di 9 si assume l'alfabeto ( a=10until z=35). Puoi trovare ulteriori informazioni sulla formattazione esatta che può essere analizzata qui per numeri in virgola mobile , interi con segno e interi senza segno .

Infine, per ogni funzione è presente anche un overload che accetta un file std::wstring come primo parametro un.

numerico in stringa

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

Questi sono più semplici, si passa il tipo numerico appropriato e si ottiene una stringa. Per le opzioni di formattazione dovresti tornare all'opzione stringsream C ++ 03 e utilizzare i manipolatori di flusso, come spiegato in un'altra risposta qui.

Come notato nei commenti, queste funzioni ricadono su una precisione di mantissa predefinita che probabilmente non è la massima precisione. Se è necessaria una maggiore precisione per la tua applicazione, è anche meglio tornare ad altre procedure di formattazione delle stringhe.

Esistono anche funzioni simili definite che vengono nominate to_wstring, queste restituiranno un file std::wstring.


3
std::to_stringperde molta precisione per i tipi in virgola mobile. Ad esempio, double f = 23.4323897462387526; std::string f_str = std::to_string(f);restituisce una stringa di 23.432390. Ciò rende impossibile eseguire il round trip dei valori in virgola mobile utilizzando queste funzioni.
fun4jimmy

@ fun4jimmy è una restrizione imposta dallo standard o dall'implementazione specifica? Lo aggiungerò alla risposta. Non che il round trip fluttui tra le corde sia mai una buona idea.
KillianDS

Lo standard C ++ dice " Restituisce: ogni funzione restituisce un oggetto stringa che contiene la rappresentazione in caratteri del valore del suo argomento che verrebbe generato chiamando sprintf(buf, fmt, val)con un identificatore di formato "% d " , "% u " , "% ld " , " % lu " , "% lld " , "% llu " , "% f " , "% f " o "% Lf " , rispettivamente, dove bufdesigna un buffer di caratteri interno di dimensioni sufficienti. " Ho dato un'occhiata al C99 standard per printf e penso che il numero di cifre decimali dipenda da#define DECIMAL_DIG infloat.h .
fun4jimmy

Bruce Dawson ha sul suo blog alcuni buoni articoli su quale precisione è necessaria per i numeri in virgola mobile .
fun4jimmy

2
Tutte queste funzioni sono influenzate dalla localizzazione globale, che può portare a problemi se si usano le librerie e soprattutto se si usano i thread. Vedi la mia domanda qui: stackoverflow.com/questions/31977457/…
Ident

86

Come convertire un numero in una stringa in C ++ 03

  1. Non utilizzare lefunzioniitoaoitofperché non sono standard e quindi non portatili.
  2. Usa flussi di stringhe

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

    Nota che puoi utilizzare flussi di stringhe anche per convertire i numeri in virgola mobile in una stringa e anche per formattare la stringa come desideri, proprio come con 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" 

    È possibile utilizzare manipolatori di flussi, come std::endl, std::hexe funzioni std::setw(), std::setprecision()ecc. Con flussi di stringhe esattamente allo stesso modo dicout

    Non confondere std::ostringstream constd::ostrstream. Quest'ultimo è deprecato

  3. Usa il cast lessicale potenziato . Se non hai familiarità con boost, è una buona idea iniziare con una piccola libreria come questa lexical_cast. Per scaricare e installare Boost e la sua documentazione vai qui . Sebbene boost non sia nello standard C ++, molte librerie di boost alla fine vengono standardizzate e boost è ampiamente considerato tra le migliori librerie C ++.

    Il cast lessicale utilizza i flussi sottostanti, quindi fondamentalmente questa opzione è la stessa della precedente, solo meno prolissa.

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

Come convertire una stringa in un numero in C ++ 03

  1. L'opzione più leggera, ereditata da C, sono le funzioni atoi(per interi (da alfabetico a intero)) e atof(per valori a virgola mobile (da alfabetico a float)). Queste funzioni accettano una stringa in stile C come argomento ( const char *) e quindi il loro utilizzo può essere considerato una pratica C ++ non propriamente buona. cplusplus.com ha una documentazione di facile comprensione sia su atoi che su atof, incluso come si comportano in caso di input errato . Tuttavia il collegamento contiene un errore in quanto, secondo lo standard, se il numero di input è troppo grande per rientrare nel tipo di destinazione, il comportamento è indefinito.

    #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. Usa flussi di stringhe (questa volta flusso di stringhe di input, istringstream). Ancora una volta, istringstream viene usato proprio come cin. Ancora una volta, non confondere istringstreamcon istrstream. Quest'ultimo è deprecato.

    #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. Usa il cast lessicale potenziato .

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

    In caso di input lexical_casterrato , genera un'eccezione di tipoboost::bad_lexical_cast


4
La documentazione di cplusplus per atoinon è eccellente, è errata. Non menziona che se il valore numerico della stringa non può essere rappresentato in int, il comportamento è indefinito. Dice invece che i valori fuori intervallo sono bloccati su INT_MAX/ INT_MIN, che non riesco a trovare né in C ++ 03 né in C89. Per input non attendibili / non verificati o quando si tratta di basi che i flussi non supportano, è necessario strtolche abbia definito il comportamento di errore. E commenti simili per atof/ strtod.
Steve Jessop

2
cplusplus.com si sbaglia su "atoi". Dice sul valore restituito "Se non è stato possibile eseguire una conversione valida, viene restituito un valore zero. Se il valore corretto non rientra nell'intervallo di valori rappresentabili, viene restituito INT_MAX o INT_MIN.", Ma la specifica dice che "Se il il valore del risultato non può essere rappresentato, il comportamento è indefinito. " e che "Fatta eccezione per il comportamento in caso di errore, sono equivalenti a (int)strtol(nptr, (char **)NULL, 10). Le funzioni atoi [...] restituiscono il valore convertito.". cplusplus.com è noto per essere un'incredibile cattiva fonte di informazioni per i principianti.
Johannes Schaub - litb

istr >> i1 >> f >> i2;manca gravemente un controllo per il successo.
sbi

4
std::to_string
Potrei

1
@ArmenTsirunyan: +10 dalla mia fine, una delle migliori risposte che abbia mai visto troppo in profondità. Grazie per la tua risposta.
Abhineet

4

In C ++ 17, le nuove funzioni std :: to_chars e std :: from_chars sono introdotte nell'intestazione charconv .

std :: to_chars è indipendente dalla locale, non allocante e non lanciabile.

Viene fornito solo un piccolo sottoinsieme di criteri di formattazione utilizzati da altre librerie (come std :: sprintf).

Da std :: to_chars , lo stesso per std :: from_chars .

La garanzia che std :: from_chars possa recuperare ogni valore a virgola mobile formattato esattamente da to_chars viene fornita solo se entrambe le funzioni provengono dalla stessa implementazione

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

Sebbene non sia completamente implementato dai compilatori, verrà sicuramente implementato.


0

Ho rubato questa comoda classe da qualche parte qui su StackOverflow per convertire qualsiasi cosa possa essere trasmessa in streaming in una stringa:

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

E poi lo usi come;

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

Abbastanza elegante!

Inoltre uso questa funzione per convertire stringhe in qualsiasi cosa che possa essere trasmessa in streaming, anche se non è molto sicura se provi ad analizzare una stringa che non contiene un numero; (e non è neanche così intelligente come l'ultimo)

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

Usare come:

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

Potresti anche volere versioni per wstrings.


5
Questo è esattamente ciò che fa boost :: lexical_cast. E boost lo fa in un modo più generico.
Armen Tsirunyan

È vero, ho passato in rassegna la prima risposta e non ho visto boost :: lexical_casts.
Viktor Sehr
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.