Cómo convertir un número a una cadena y viceversa en C ++

120

Dado que esta pregunta se hace todas las semanas, estas preguntas frecuentes pueden ayudar a muchos usuarios.

  • Cómo convertir un número entero en una cadena en C ++

  • cómo convertir una cadena en un entero en C ++

  • cómo convertir un número de punto flotante en una cadena en C ++

  • cómo convertir una cadena en un número de punto flotante en C ++

Armen Tsirunyan
fuente
Para conversiones como estas, tengo un marcador converttypes.com
Firzok Nadeem

Respuestas:

129

Actualización para C ++ 11

Como C++11estándar, la conversión de cadena a número y viceversa están incorporadas en la biblioteca estándar. Todas las funciones siguientes están presentes en <string>(según el párrafo 21.5).

cadena a numérico

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

Cada uno de estos toma una cadena como entrada e intentará convertirla en un número. Si no se pudo construir un número válido, por ejemplo porque no hay datos numéricos o el número está fuera del rango para el tipo, se lanza una excepción ( std::invalid_argumento std::out_of_range).

Si la conversión tuvo éxito y idxno lo es 0, idxcontendrá el índice del primer carácter que no se usó para decodificar. Este podría ser un índice detrás del último carácter.

Finalmente, los tipos integrales permiten especificar una base, para dígitos mayores a 9, se asume el alfabeto ( a=10hasta z=35). Puede encontrar más información sobre el formato exacto que se puede analizar aquí para números de punto flotante , enteros con signo y enteros sin signo .

Finalmente, para cada función también hay una sobrecarga que acepta a std::wstringcomo primer parámetro.

numérico a cadena

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

Estos son más sencillos, pasa el tipo numérico apropiado y obtiene una cadena de regreso. Para las opciones de formato, debe volver a la opción de secuencia de cadenas de C ++ 03 y usar manipuladores de secuencia, como se explica en otra respuesta aquí.

Como se señaló en los comentarios, estas funciones recurren a una precisión de mantisa predeterminada que probablemente no sea la precisión máxima. Si se requiere más precisión para su aplicación, también es mejor volver a otros procedimientos de formateo de cadenas.

También hay funciones similares definidas que se nombran to_wstring, estas devolverán un std::wstring.

KillianDS
fuente
3
std::to_stringpierde mucha precisión para los tipos de coma flotante. Por ejemplo, double f = 23.4323897462387526; std::string f_str = std::to_string(f);devuelve una cadena de 23,432390. Esto hace que sea imposible redondear valores de coma flotante utilizando estas funciones.
fun4jimmy
@ fun4jimmy ¿es esta una restricción impuesta por el estándar o una implementación específica? Lo agregaré a la respuesta. No es que los flotadores de ida y vuelta a través de cuerdas sean una buena idea.
KillianDS
El estándar C ++ dice " Devuelve: cada función devuelve un objeto de cadena que contiene la representación de caracteres del valor de su argumento que se generaría al llamar sprintf(buf, fmt, val)con un especificador de formato de "% d " , "% u " , "% ld " , " % lu " , "% lld " , "% llu " , "% f " , "% f " o "% Lf " , respectivamente, donde bufdesigna un búfer de caracteres interno de tamaño suficiente. "Eché un vistazo al estándar C99 para printf y creo que el número de decimales depende de #define DECIMAL_DIGenflotar.h .
fun4jimmy
Bruce Dawson tiene algunos buenos artículos sobre qué precisión se necesita para disparar números de punto flotante en su blog .
fun4jimmy
2
Todas estas funciones se ven afectadas por la configuración regional global, lo que puede generar problemas si utiliza bibliotecas y, especialmente, si utiliza subprocesos. Vea mi pregunta aquí: stackoverflow.com/questions/31977457/…
Ident
86

Cómo convertir un número en una cadena en C ++ 03

  1. No utilice lasfuncionesitoaoitofporque no son estándar y, por lo tanto, no son portátiles.
  2. Usar secuencias de cadenas

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

    Tenga en cuenta que también puede usar secuencias de cadenas para convertir números de punto flotante en cadenas, y también para formatear la cadena como desee, al igual que 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" 

    Puede usar manipuladores de flujo, como std::endl, std::hexy funciones std::setw(), std::setprecision()etc. con flujos de cadena exactamente de la misma manera que concout

    No confunda std::ostringstream constd::ostrstream. Este último está en desuso

  3. Utilice potenciar el elenco léxico . Si no está familiarizado con boost, es una buena idea comenzar con una biblioteca pequeña como esta lexical_cast. Para descargar e instalar boost y su documentación, vaya aquí . Aunque boost no está en el estándar C ++, muchas bibliotecas de boost se estandarizan eventualmente y boost se considera una de las mejores bibliotecas de C ++.

    El elenco léxico usa secuencias debajo, así que básicamente esta opción es la misma que la anterior, solo que menos detallada.

    #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ómo convertir una cadena en un número en C ++ 03

  1. La opción más ligera, heredada de C, son las funciones atoi(para enteros (alfabético a entero)) y atof(para valores de punto flotante (alfabético a flotante)). Estas funciones toman una cadena de estilo C como argumento ( const char *) y, por lo tanto, su uso puede considerarse una práctica no exactamente buena en C ++. cplusplus.com tiene documentación fácil de entender tanto sobre atoi como sobre atof, que incluye cómo se comportan en caso de una entrada incorrecta. Sin embargo, el vínculo contiene un error en el sentido de que, según el estándar, si el número de entrada es demasiado grande para caber en el tipo de destino, el comportamiento no está definido.

    #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. Utilice secuencias de cadenas (esta vez, secuencia de cadenas de entrada istringstream). Nuevamente, istringstream se usa igual que cin. Nuevamente, no confunda istringstreamcon istrstream. Este último está en desuso.

    #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. Utilice potenciar el elenco léxico .

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

    En caso de una mala entrada, lexical_castlanza una excepción de tipoboost::bad_lexical_cast

Armen Tsirunyan
fuente
4
La documentación de cplusplus atoino es excelente, es incorrecta. No menciona que si el valor numérico de la cadena no se puede representar int, entonces el comportamiento no está definido. En cambio, dice que los valores fuera de rango están sujetos a INT_MAX/ INT_MIN, que no puedo encontrar ni en C ++ 03 ni en C89. Para entradas no confiables / no verificadas, o cuando se trata de bases que las transmisiones no admiten, necesita strtol, que tiene un comportamiento de error definido. Y comentarios similares para atof/ strtod.
Steve Jessop
2
cplusplus.com se equivoca sobre "atoi". Dice sobre el valor de retorno "Si no se pudo realizar una conversión válida, se devuelve un valor cero. Si el valor correcto está fuera del rango de valores representables, se devuelve INT_MAX o INT_MIN", pero la especificación dice que "Si el el valor del resultado no se puede representar, el comportamiento no está definido ". y que "Excepto por el comportamiento de error, son equivalentes a (int)strtol(nptr, (char **)NULL, 10). Las funciones [...] atoi devuelven el valor convertido". cplusplus.com es conocido por ser una increíble mala fuente de información para principiantes.
Johannes Schaub - litb
istr >> i1 >> f >> i2;pierde gravemente un control de éxito.
sbi
4
Quizás desee agregarstd::to_string
Pubby
1
@ArmenTsirunyan: +10 de mi parte, una de las mejores respuestas que he visto en profundidad. Gracias por tu respuesta.
Abhineet
4

En C ++ 17, las nuevas funciones std :: to_chars y std :: from_chars se introducen en el encabezado charconv .

std :: to_chars es independiente de la configuración regional, no asigna ni lanza.

Solo se proporciona un pequeño subconjunto de políticas de formato utilizadas por otras bibliotecas (como std :: sprintf).

Desde std :: to_chars , lo mismo para std :: from_chars .

La garantía de que std :: from_chars puede recuperar cada valor de punto flotante formateado por to_chars exactamente solo se proporciona si ambas funciones son de la misma implementación

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

Aunque no está completamente implementado por los compiladores, definitivamente se implementará.

JiaHao Xu
fuente
0

Robé esta clase conveniente de algún lugar aquí en StackOverflow para convertir cualquier cosa que se pueda transmitir en una cadena:

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

Y luego lo usas como;

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

¡Muy ingenioso!

También utilizo esta función para convertir cadenas en cualquier cosa que se pueda transmitir, aunque no es muy seguro si intenta analizar una cadena que no contiene un número; (y tampoco es tan inteligente como el anterior)

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

Usar como:

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

Es posible que también desee versiones para wstrings.

Viktor Sehr
fuente
5
Esto es exactamente lo que hace boost :: lexical_cast. Y boost lo hace de una manera más genérica.
Armen Tsirunyan
Es cierto, hojeé la primera respuesta y no vi el boost :: lexical_casts.
Viktor Sehr