Como converter um número em string e vice-versa em C ++


120

Como essa pergunta é feita toda semana, essas Perguntas frequentes podem ajudar muitos usuários.

  • Como converter um número inteiro em uma seqüência de caracteres em C ++

  • como converter uma seqüência de caracteres em um número inteiro em C ++

  • como converter um número de ponto flutuante em uma string em C ++

  • como converter uma seqüência de caracteres em um número de ponto flutuante em C ++


Para conversões como essas, tenho um marcador converttypes.com
Firzok Nadeem

Respostas:


129

Atualização para C ++ 11

A partir do C++11padrão, a conversão de string para número e vice-versa são incorporadas à biblioteca padrão. Todas as seguintes funções estão presentes em <string>(conforme o parágrafo 21.5).

string para 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 um deles usa uma string como entrada e tenta convertê-la em um número. Se nenhum número válido puder ser construído, por exemplo, porque não há dados numéricos ou o número está fora do intervalo para o tipo, uma exceção é lançada ( std::invalid_argumentou std::out_of_range).

Se a conversão for bem-sucedida e idxnão for 0, idxconterá o índice do primeiro caractere que não foi usado para decodificação. Este pode ser um índice por trás do último caractere.

Finalmente, os tipos integrais permitem especificar uma base; para dígitos maiores que 9, o alfabeto é assumido ( a=10até z=35). Você pode encontrar mais informações sobre a exata formatação que poderão analisado aqui para números de ponto flutuante , assinado inteiros e inteiros sem sinal .

Finalmente, para cada função, há também uma sobrecarga que aceita a std::wstringcomo primeiro parâmetro.

numérico para string

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

Isso é mais direto: você passa o tipo numérico apropriado e recebe uma string de volta. Para opções de formatação, você deve voltar à opção C ++ 03 stringsream e usar manipuladores de fluxo, conforme explicado em outra resposta aqui.

Conforme observado nos comentários, essas funções retornam a uma precisão mantissa padrão que provavelmente não é a precisão máxima. Se for necessária mais precisão para o seu aplicativo, também é melhor voltar para outros procedimentos de formatação de string.

Também existem funções semelhantes definidas que são nomeadas to_wstring; elas retornarão a std::wstring.


3
std::to_stringperde muita precisão para tipos de ponto flutuante. Por exemplo, double f = 23.4323897462387526; std::string f_str = std::to_string(f);retorna uma sequência de 23.432390. Isso torna impossível arredondar os valores dos pontos flutuantes usando essas funções.
fun4jimmy

@ fun4jimmy isso é uma restrição imposta pelo padrão ou implementação específica? Irá adicioná-lo à resposta. Não é sempre uma boa ideia fazer viagens de ida e volta por cordas.
KillianDS

O padrão C ++ diz " Retorna: cada função retorna um objeto de seqüência de caracteres que contém a representação de caractere do valor de seu argumento que seria gerado pela chamada sprintf(buf, fmt, val)com um especificador de formato "% d " , "% u " , "% ld " , " % lu " , "% lld " , "% llu " , "% f " , "% f " ou "% Lf " , respectivamente, em que bufdesigna um buffer de caracteres interno de tamanho suficiente. "Eu tinha um olhar para o C99 padrão para printf e eu acho que o número de casas decimais é dependente #define DECIMAL_DIGemfloat.h .
fun4jimmy

Bruce Dawson tem alguns bons artigos sobre qual precisão é necessária para números de ponto flutuante de disparo redondo em seu blog .
fun4jimmy

2
Todas essas funções são afetadas pelo código do idioma global, o que pode causar problemas se você usar bibliotecas e, principalmente, se usar segmentos. Veja minha pergunta aqui: stackoverflow.com/questions/31977457/…
Ident

86

Como converter um número em uma seqüência de caracteres em C ++ 03

  1. Não use asfunçõesitoaouitofporque elas não são padrão e, portanto, não são portáteis.
  2. Use fluxos de sequência

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

    Observe que você pode usar fluxos de sequência também para converter números de ponto flutuante em sequência e também para formatar a sequência como desejar, assim como com 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" 

    Você pode usar manipuladores de fluxo, tais como std::endl, std::hexe funções std::setw(), std::setprecision()etc., com correntes de cordas exatamente da mesma maneira que comcout

    Não confunda std::ostringstream comstd::ostrstream. Este último está obsoleto

  3. Usar boost elenco lexical . Se você não está familiarizado com o boost, é uma boa idéia começar com uma pequena biblioteca como esta lexical_cast. Para baixar e instalar o boost e sua documentação, clique aqui . Embora o boost não esteja no padrão C ++, muitas bibliotecas de boost são padronizadas eventualmente e o boost é amplamente considerado uma das melhores bibliotecas C ++.

    O elenco lexical usa fluxos por baixo, então basicamente essa opção é a mesma que a anterior, apenas menos detalhada.

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

Como converter uma seqüência de caracteres em um número em C ++ 03

  1. A opção mais leve, herdada de C, são as funções atoi(para números inteiros (em ordem alfabética para número inteiro)) e atof(para valores de ponto flutuante (em ordem alfabética para flutuar)). Essas funções aceitam uma string no estilo C como argumento ( const char *) e, portanto, seu uso pode ser considerado uma prática não exatamente boa do C ++. O cplusplus.com possui uma documentação fácil de entender, tanto no atoi quanto no atof, incluindo como eles se comportam em caso de insatisfação . No entanto, o link contém um erro, de acordo com o padrão, se o número de entrada for muito grande para caber no tipo de destino, o comportamento será indefinido.

    #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. Use fluxos de cadeia (desta vez insira fluxo de cadeia istringstream). Novamente, o istringstream é usado da mesma maneira cin. Mais uma vez, não confunda istringstreamcom istrstream. O último está obsoleto.

    #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. Usar elenco lexical de reforço .

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

    No caso de uma entrada incorreta, lexical_castlança uma exceção do tipoboost::bad_lexical_cast


4
A documentação do cplusplus para atoinão é excelente, está incorreta. Ele não menciona que, se o valor numérico da sequência não puder ser representado int, o comportamento será indefinido. Em vez disso, diz que valores fora do intervalo estão fixados em INT_MAX/ INT_MIN, o que não consigo encontrar no C ++ 03 ou no C89. Para entradas não confiáveis ​​/ não verificadas ou ao lidar com bases que os fluxos não suportam, você precisa strtoldefinir um comportamento de erro. E comentários semelhantes para atof/ strtod.
21711 Steve Jobs (

2
cplusplus.com está errado sobre "atoi". Ele diz sobre o valor de retorno "Se nenhuma conversão válida puder ser executada, um valor zero será retornado. Se o valor correto estiver fora do intervalo de valores representáveis, INT_MAX ou INT_MIN será retornado.", Mas a especificação diz que "Se o o valor do resultado não pode ser representado, o comportamento é indefinido. " e que "Exceto pelo comportamento em erro, eles são equivalentes a (int)strtol(nptr, (char **)NULL, 10). As funções [...] atoi retornam o valor convertido.". cplusplus.com é conhecido por ser uma incrível fonte ruim de informações para iniciantes.
Johannes Schaub - litb 13/03

istr >> i1 >> f >> i2;falta muito de um cheque de sucesso.
Sbi

4
Pode querer adicionarstd::to_string
Pubby

1
@ArmenTsirunyan: +10 do meu final, uma das melhores respostas que já vi isso em profundidade. Obrigado pela sua resposta.
Abhineet

4

No C ++ 17, novas funções std :: to_chars e std :: from_chars são introduzidas no cabeçalho charconv .

std :: to_chars é independente da localidade, não está alocando e não está jogando.

Somente um pequeno subconjunto de políticas de formatação usado por outras bibliotecas (como std :: sprintf) é fornecido.

De std :: to_chars , o mesmo para std :: from_chars .

A garantia de que std :: from_chars pode recuperar todos os valores de ponto flutuante formatados por to_chars exatamente é fornecida apenas se as duas funções forem da mesma implementação

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

Embora não seja totalmente implementado pelos compiladores, definitivamente será implementado.


0

Eu roubei essa classe conveniente de algum lugar aqui no StackOverflow para converter qualquer coisa streamable em uma string:

// 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 então você o usa como;

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

Bastante bacana!

Também uso essa função para converter seqüências de caracteres para qualquer coisa que possa ser estriada, apesar de não ser muito seguro se você tentar analisar uma sequência que não contém um número; (e não é tão inteligente quanto o último)

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

Use como:

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

Você também pode querer versões para wstrings.


5
É exatamente isso que o boost :: lexical_cast faz. E o impulso faz isso de maneira mais genérica.
Armen Tsirunyan

É verdade que passei os olhos pela primeira resposta e não vi o boost :: lexical_casts.
Viktor Sehr
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.