Como converter um std :: string para const char * ou char *?

Como posso converter um std::string para um char* ou um const char* ?

Se você quer apenas passar um std::string para uma function que precisa const char* você pode usar

 std::string str; const char * c = str.c_str(); 

Se você quiser obter uma cópia gravável, como char * , você pode fazer isso com isto:

 std::string str; char * writable = new char[str.size() + 1]; std::copy(str.begin(), str.end(), writable); writable[str.size()] = '\0'; // don't forget the terminating 0 // don't forget to free the string after finished using it delete[] writable; 

Edit : Observe que o acima não é exceção segura. Se alguma coisa entre a new chamada e a chamada de delete emitida, você vazará memory, já que nada chamará delete automaticamente. Existem duas maneiras imediatas de resolver isso.

boost :: scoped_array

boost::scoped_array irá apagar a memory para você ao sair do escopo:

 std::string str; boost::scoped_array writable(new char[str.size() + 1]); std::copy(str.begin(), str.end(), writable.get()); writable[str.size()] = '\0'; // don't forget the terminating 0 // get the char* using writable.get() // memory is automatically freed if the smart pointer goes // out of scope 

std :: vector

Esta é a maneira padrão (não requer nenhuma biblioteca externa). Você usa std::vector , que gerencia completamente a memory para você.

 std::string str; std::vector writable(str.begin(), str.end()); writable.push_back('\0'); // get the char* using &writable[0] or &*writable.begin() 

Dada diga …

 std::string x = "hello"; 

Obtendo um char * `ou` const char * `de um` string`

Como obter um ponteiro de caractere válido enquanto x permanecer no escopo e não for modificado

C ++ 11 simplifica as coisas; o seguinte todos dão access ao mesmo buffer de string interno:

 const char* p_c_str = x.c_str(); const char* p_data = x.data(); const char* p_x0 = &x[0]; char* p_x0_rw = &x[0]; // compiles iff x is not const... 

Todos os pointers acima terão o mesmo valor – o endereço do primeiro caractere no buffer. Mesmo uma string vazia tem um “primeiro caractere no buffer”, porque o C ++ 11 garante manter sempre um caractere terminador NUL / 0 extra após o conteúdo da string explicitamente designado (por exemplo, std::string("this\0that", 9) terá um buffer contendo "this\0that\0" ).

Dado qualquer um dos indicadores acima:

 char c = p[n]; // valid for n <= x.size() // ie you can safely read the NUL at p[x.size()] 

Apenas para o ponteiro não const de &x[0] :

 p_x0_rw[n] = c; // valid for n <= x.size() - 1 // ie don't overwrite the implementation maintained NUL 

Escrever um NUL em outro lugar na string não altera o size() da string size() ; string 's tem permissão para conter qualquer número de NULs - eles não recebem nenhum tratamento especial por std::string (o mesmo em C ++ 03).

Em C ++ 03 , as coisas foram consideravelmente mais complicadas (principais diferenças destacadas ):

  • x.data()

    • retorna const char* para o buffer interno da string que não foi requerido pelo Standard para concluir com um NUL (ie pode ser ['h', 'e', 'l', 'l', 'o'] seguido por não inicializado ou valores de lixo, com accesss acidentais para ter comportamento indefinido ).
      • x.size() caracteres x.size() são seguros para leitura, ou seja, x[0] a x[x.size() - 1]
      • para strings vazias, você está garantido algum ponteiro não-NULL ao qual 0 pode ser adicionado com segurança (hurray!), mas você não deve fazer a referência a esse ponteiro.
  • &x[0]

    • para strings vazias isso tem comportamento indefinido (21.3.4)
      • por exemplo, dado f(const char* p, size_t n) { if (n == 0) return; ...whatever... } f(const char* p, size_t n) { if (n == 0) return; ...whatever... } você não deve chamar f(&x[0], x.size()); quando x.empty() - apenas use f(x.data(), ...) .
    • caso contrário, conforme x.data() mas:
      • para non- const x isto produz um ponteiro não const char* ; você pode sobrescrever o conteúdo da string
  • x.c_str()

    • retorna const char* para uma representação ASCIIZ (terminada em NUL) do valor (ie ['h', 'e', ​​'l', 'l', 'o', '\ 0']).
    • Embora poucas implementações escolhessem, o C ++ 03 Standard foi redigido para permitir que a implementação da cadeia de caracteres criasse um buffer terminado em NUL distinto rapidamente , a partir do buffer potencialmente não-terminado em NUL "exposto" por x.data() e &x[0]
    • x.size() + 1 caracteres são seguros para leitura.
    • garantido seguro mesmo para strings vazias (['\ 0']).

Consequências do access a índices legais externos

Qualquer que seja a maneira de obter um ponteiro, você não deve acessar a memory mais adiante do ponteiro do que os caracteres garantidos presentes nas descrições acima. Tentativas de fazer isso têm um comportamento indefinido , com uma chance muito real de falhas de aplicativos e resultados de lixo, mesmo para leituras, e adicionalmente dados de atacado, corrupção de pilha e / ou vulnerabilidades de segurança para gravações.

Quando esses indicadores são invalidados?

Se você chamar alguma function de membro de string que modifica a string ou reserva capacidade adicional, todos os valores de ponteiro retornados antecipadamente por qualquer um dos methods acima serão invalidados . Você pode usar esses methods novamente para obter outro ponteiro. (As regras são as mesmas que para os iteradores em string s).

Veja também Como obter um ponteiro de caractere válido mesmo depois de x deixar o escopo ou ser modificado mais abaixo ...

Então, qual é melhor usar?

No C ++ 11, use .c_str() para dados .data() e .data() para dados "binários" (explicados mais adiante).

Em C ++ 03, use .c_str() menos que esteja certo que .data() seja adequado e prefira .data() over &x[0] , pois é seguro para cadeias vazias ....

... tente entender o programa o suficiente para usar data() quando apropriado, ou você provavelmente cometerá outros erros ...

O caractere ASCII NUL '\ 0' garantido por .c_str() é usado por muitas funções como um valor sentinela que denota o fim de dados relevantes e seguros para access. Isso se aplica a funções do tipo C ++ - como, por exemplo, fstream::fstream(const char* filename, ...) e funções compartilhadas com C como strchr() e printf() .

Dadas as .c_str() de .c_str() do C ++ 03 sobre o buffer retornado são um super conjunto de .data() , você sempre pode usar com segurança o .c_str() , mas as pessoas às vezes não o fazem porque:

  • O uso de .data() comunica com outros programadores que lêem o código-fonte de que os dados não são ASCIIZ (ao invés disso, você está usando a string para armazenar um bloco de dados (que às vezes nem é realmente textual)) ou que você re passando para outra function que a trata como um bloco de dados "binários". Isso pode ser uma percepção crucial para garantir que as alterações no código de outros programadores continuem a manipular os dados adequadamente.
  • Somente C ++ 03: há uma pequena chance de que sua implementação de string precise fazer alguma alocação de memory extra e / ou cópia de dados para preparar o buffer terminado em NUL.

Como uma dica adicional, se os parâmetros de uma function requerem o ( const ) char* mas não insistem em obter x.size() , a function provavelmente precisa de uma input ASCIIZ, então .c_str() é uma boa escolha (a function precisa para saber onde o texto termina de alguma forma, por isso, se não for um parâmetro separado, só pode ser uma convenção como um prefixo de comprimento ou sentinela ou algum comprimento fixo esperado.

Como obter um ponteiro de caractere válido mesmo depois que x deixar o escopo ou for modificado

Você precisará copiar o conteúdo da string x para uma nova área de memory fora de x . Esse buffer externo pode estar em muitos lugares, como outra variável de array de caracteres ou de string , pode ou não ter um tempo de vida diferente de x devido a estar em um escopo diferente (por exemplo, namespace, global, static, heap, memory compartilhada, memory mapeada Arquivo).

Para copiar o texto de std::string x em uma matriz de caracteres independente:

 // USING ANOTHER STRING - AUTO MEMORY MANAGEMENT, EXCEPTION SAFE std::string old_x = x; // - old_x will not be affected by subsequent modifications to x... // - you can use `&old_x[0]` to get a writable char* to old_x's textual content // - you can use resize() to reduce/expand the string // - resizing isn't possible from within a function passed only the char* address std::string old_x = x.c_str(); // old_x will terminate early if x embeds NUL // Copies ASCIIZ data but could be less efficient as it needs to scan memory to // find the NUL terminator indicating string length before allocating that amount // of memory to copy into, or more efficient if it ends up allocating/copying a // lot less content. // Example, x == "ab\0cd" -> old_x == "ab". // USING A VECTOR OF CHAR - AUTO, EXCEPTION SAFE, HINTS AT BINARY CONTENT, GUARANTEED CONTIGUOUS EVEN IN C++03 std::vector old_x(x.data(), x.data() + x.size()); // without the NUL std::vector old_x(x.c_str(), x.c_str() + x.size() + 1); // with the NUL // USING STACK WHERE MAXIMUM SIZE OF x IS KNOWN TO BE COMPILE-TIME CONSTANT "N" // (a bit dangerous, as "known" things are sometimes wrong and often become wrong) char y[N + 1]; strcpy(y, x.c_str()); // USING STACK WHERE UNEXPECTEDLY LONG x IS TRUNCATED (eg Hello\0->Hel\0) char y[N + 1]; strncpy(y, x.c_str(), N); // copy at most N, zero-padding if shorter y[N] = '\0'; // ensure NUL terminated // USING THE STACK TO HANDLE x OF UNKNOWN (BUT SANE) LENGTH char* y = alloca(x.size() + 1); strcpy(y, x.c_str()); // USING THE STACK TO HANDLE x OF UNKNOWN LENGTH (NON-STANDARD GCC EXTENSION) char y[x.size() + 1]; strcpy(y, x.c_str()); // USING new/delete HEAP MEMORY, MANUAL DEALLOC, NO INHERENT EXCEPTION SAFETY char* y = new char[x.size() + 1]; strcpy(y, x.c_str()); // or as a one-liner: char* y = strcpy(new char[x.size() + 1], x.c_str()); // use y... delete[] y; // make sure no break, return, throw or branching bypasses this // USING new/delete HEAP MEMORY, SMART POINTER DEALLOCATION, EXCEPTION SAFE // see boost shared_array usage in Johannes Schaub's answer // USING malloc/free HEAP MEMORY, MANUAL DEALLOC, NO INHERENT EXCEPTION SAFETY char* y = strdup(x.c_str()); // use y... free(y); 

Outras razões para querer um char* ou const char* gerado a partir de uma string

Então, acima você viu como obter um ( const ) char* , e como fazer uma cópia do texto independente da string original, mas o que você pode fazer com isso? Um punhado random de exemplos ...

  • forneça access ao código "C" ao texto da string C ++, como em printf("x is '%s'", x.c_str());
  • Copie o texto de x para um buffer especificado pelo chamador da sua function (por exemplo, strncpy(callers_buffer, callers_buffer_size, x.c_str()) ), ou memory volátil usada para o dispositivo I / O (por exemplo, for (const char* p = x.c_str(); *p; ++p) *p_device = *p; )
  • acrescente o texto de x a uma matriz de caracteres que já contenha algum texto ASCIIZ (por exemplo, strcat(other_buffer, x.c_str()) ) - strcat(other_buffer, x.c_str()) cuidado para não sobrecarregar o buffer (em muitas situações você pode precisar usar o strncat )
  • retorna um const char* ou char* de uma function (talvez por razões históricas - o cliente está usando sua API existente - ou para compatibilidade com C você não quer retornar um std::string , mas quer copiar os dados da sua string em algum lugar para o chamador)
    • tenha cuidado para não retornar um ponteiro que possa ser desreferenciado pelo chamador após uma variável de string local para a qual esse ponteiro apontado tenha deixado o escopo
    • alguns projetos com objects compartilhados compilados / vinculados para diferentes implementações std::string (por exemplo, STLport e compilador-nativo) podem passar dados como ASCIIZ para evitar conflitos

Use o método .c_str() para const char * .

Você pode usar o &mystring[0] para obter um char * , mas há algumas pegadinhas: você não terá necessariamente uma cadeia terminada com zero e não poderá alterar o tamanho da string. Você especialmente tem que ter cuidado para não adicionar caracteres após o final da seqüência de caracteres ou você obterá uma sobrecarga de buffer (e provável acidente).

Não havia garantia de que todos os caracteres seriam parte do mesmo buffer contíguo até o C ++ 11, mas, na prática, todas as implementações conhecidas do std::string funcionavam dessa maneira; consulte “& s [0]” aponta para caracteres contíguos em um std :: string? .

Observe que muitas funções de membros de string realocarão o buffer interno e invalidarão todos os pointers que você possa ter salvo. Melhor usá-los imediatamente e depois descartar.

C ++ 17

O C ++ 17 (padrão futuro) altera a sinopse do modelo basic_string adicionando uma sobrecarga de data() não const data() :

charT* data() noexcept;

Retorna: Um ponteiro p tal que p + i == & operador para cada i em [0, tamanho ()].


CharT const * from std::basic_string

 std::string const cstr = { "..." }; char const * p = cstr.data(); // or .c_str() 

CharT * de std::basic_string

 std::string str = { "..." }; char * p = str.data(); 

C ++ 11

CharT const * from std::basic_string

 std::string str = { "..." }; str.c_str(); 

CharT * de std::basic_string

Do C ++ 11 em diante, o padrão diz:

  1. Os objects tipo char em um object basic_string devem ser armazenados contiguamente. Isto é, para qualquer object basic_string s , a identidade &*(s.begin() + n) == &*s.begin() + n deve ser válida para todos os valores de n tais que 0 <= n < s.size()

  1. const_reference operator[](size_type pos) const;
    reference operator[](size_type pos);

    Retorna: *(begin() + pos) se pos < size() , caso contrário, uma referência a um object do tipo CharT com o valor CharT() ; o valor referenciado não deve ser modificado.


  1. const charT* c_str() const noexcept;
    const charT* data() const noexcept;

    Retorna: Um ponteiro p tal que p + i == &operator[](i) para cada i em [0,size()] .

Existem maneiras possíveis separáveis ​​de obter um ponteiro de caractere não const.

1. Use o armazenamento contíguo do C ++ 11

 std::string foo{"text"}; auto p = &*foo.begin(); 

Pró

  • Simples e curto
  • Rápido (único método sem cópia envolvida)

Contras

  • Final '\0' não deve ser alterado / não necessariamente parte da memory não-const.

2. Use std::vector

 std::string foo{"text"}; std::vector fcv(foo.data(), foo.data()+foo.size()+1u); auto p = fcv.data(); 

Pró

  • Simples
  • Manuseio automático de memory
  • Dinâmico

Contras

  • Requer cópia de string

3. Use std::array se N for constante de tempo de compilation (e pequeno o suficiente)

 std::string foo{"text"}; std::array fca; std::copy(foo.data(), foo.data()+foo.size()+1u, fca.begin()); 

Pró

  • Simples
  • Manipulação de memory de pilha

Contras

  • Estático
  • Requer cópia de string

4. Alocação de memory bruta com exclusão automática de armazenamento

 std::string foo{ "text" }; auto p = std::make_unique(foo.size()+1u); std::copy(foo.data(), foo.data() + foo.size() + 1u, &p[0]); 

Pró

  • Pegada de memory pequena
  • Exclusão automática
  • Simples

Contras

  • Requer cópia de string
  • Estático (uso dynamic requer muito mais código)
  • Menos resources que vetor ou matriz

5. Alocação de memory bruta com manuseio manual

 std::string foo{ "text" }; char * p = nullptr; try { p = new char[foo.size() + 1u]; std::copy(foo.data(), foo.data() + foo.size() + 1u, p); // handle stuff with p delete[] p; } catch (...) { if (p) { delete[] p; } throw; } 

Pró

  • Máximo 'controle'

Vigarista

  • Requer cópia de string
  • Máxima responsabilidade / suscetibilidade por erros
  • Complexo

Eu estou trabalhando com uma API com um monte de funções obter como input um char* .

Eu criei uma pequena class para enfrentar este tipo de problema, eu implementei o idioma RAII.

 class DeepString { DeepString(const DeepString& other); DeepString& operator=(const DeepString& other); char* internal_; public: explicit DeepString( const string& toCopy): internal_(new char[toCopy.size()+1]) { strcpy(internal_,toCopy.c_str()); } ~DeepString() { delete[] internal_; } char* str() const { return internal_; } const char* c_str() const { return internal_; } }; 

E você pode usá-lo como:

 void aFunctionAPI(char* input); // other stuff aFunctionAPI("Foo"); //this call is not safe. if the function modified the //literal string the program will crash std::string myFoo("Foo"); aFunctionAPI(myFoo.c_str()); //this is not compiling aFunctionAPI(const_cast(myFoo.c_str())); //this is not safe std::string //implement reference counting and //it may change the value of other //strings as well. DeepString myDeepFoo(myFoo); aFunctionAPI(myFoo.str()); //this is fine 

Eu chamei a class DeepString porque ela está criando uma cópia profunda e única (o DeepString não é copiável) de uma string existente.

 char* result = strcpy((char*)malloc(str.length()+1), str.c_str()); 

Apenas veja isto:

 string str1("stackoverflow"); const char * str2 = str1.c_str(); 

No entanto, observe que isso retornará um const char * .Para um char * , use o strcpy para copiá-lo em outro array char .

Tente isso

 std::string s(reinterpret_cast(Data), Size);