Como posso converter um std::string
para um char*
ou um const char*
?
Se você só quer passar um std::string
para uma função que precisa de const char*
você pode utilizar
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;
**Editar***: Repare que o acima não é uma excepção segura. Se algo entre a chamada nova' e a chamada
delete' for lançado, você irá vazar memória, pois nada irá chamar `delete' para você automaticamente. Há duas maneiras imediatas de resolver isso.
boost::scoped_array` irá apagar a memória para você ao sair do escopo:
std::string str;
boost::scoped_array<char> 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
Esta é a forma padrão (não requer nenhuma biblioteca externa). Você utiliza std::vector
, que gerencia completamente a memória para você.
std::string str;
std::vector<char> writable(str.begin(), str.end());
writable.push_back('\0');
// get the char* using &writable[0] or &*writable.begin()
Dito de outra forma...
std::string x = "hello";
const char* p_c_str = x.c_str();
const char* p_data = x.data();
char* p_writable_data = x.data(); // for non-const x from C++17
const char* p_x0 = &x[0];
char* p_x0_rw = &x[0]; // compiles iff x is not const...
Todos os indicadores acima conterão o mesmo valor * - o endereço do primeiro caractere no buffer. Mesmo uma string vazia tem um "primeiro caractere no buffer" porque C++11 garante manter sempre um caractere terminal NUL/0 extra após o conteúdo da string explicitamente atribuído (por exemplo std::string("this\0that", 9)
terá um buffer contendo "this\0that\0"
).
Dada qualquer uma das indicações acima:
char c = p[n]; // valid for n <= x.size()
// i.e. you can safely read the NUL at p[x.size()]
Apenas para o ponteiro não-constituinte p_dados_escritíveis' e de
&x[0]`:
p_writable_data[n] = c;
p_x0_rw[n] = c; // valid for n <= x.size() - 1
// i.e. don't overwrite the implementation maintained NUL
Escrever um NUL em outro lugar na string não muda a string
's size()
; string
's podem conter qualquer número de NULs - eles não recebem tratamento especial por std::string
(o mesmo em C++03).
Em C+++03**, as coisas eram consideravelmente mais complicadas (diferenças chave aluzadas****):
x.data()
const char*
para a string's buffer interno que era't exigido pelo Standard para concluir com um NUL (ou seja, pode ser ['h', 'e', 'l', 'l', 'o']
seguido por valores não inicializados ou de lixo, com acessos acidentais com comportamento indefinido).x.size()
caracteres são seguros de ler, ou seja, x[0]
até x[x.size() - 1]
&x[0]
f(const char* p, size_t n) { if (n == 0) return; ...whatever... }
você deve chamar f(&x[0], x.size()));
quando x.empty()
- basta utilizar f(x.data(), ...)
.x.data()
mas:const
x
isto produz um ponteiro non-const
char*
; você pode sobrescrever o conteúdo da stringx.c_str()
const char*
a uma representação ASCIIZ (terminada NUL) do valor (i.e. ['h', 'e', 'l', 'l', 'o', '\0']).x.data()
e &x[0]
x.size()
+ 1 caracteres são seguros de serem lidos.string
que modifica a string
ou reserva mais capacidade, quaisquer valores de ponteiro retornados antecipadamente por qualquer um dos métodos acima são invalidados. Você pode utilizar esses métodos novamente para obter outro ponteiro. (As regras são as mesmas que para iteradores em string
s).
Veja também Como obter um ponteiro de caracteres válido mesmo após o x
sair do escopo ou ser modificado mais adiante abaixo de....
Então, o que é melhor a utilizar?De C++11, utilize .c_str()
para dados ASCIIZ, e .data()
para "binary" dados (explicado mais abaixo).
Em C+++03, utilize .c_str()
a menos que seja certo que .data()
seja adequado, e prefira .data()
a &x[0]
as it's safe for empty strings....
...tente entender o programa o suficiente para utilizar data()
quando apropriado, ou você'provavelmente cometerá outros erros...
O ASCII NUL '\0' caracter garantido por .c_str()
é utilizado por muitas funções como um valor sentinela denotando o fim de dados relevantes e de acesso seguro. Isto se aplica tanto a funções C++ como fstream::fstream(const char* filename, ...)
quanto a funções compartilhadas-com-C como strchr()
, e printf()
.
Dado que C+++03's .c_str()
's garantias sobre o buffer retornado são um super conjunto de .data()
's, você pode sempre utilizar com segurança .c_str()
, mas as pessoas às vezes não o fazem't porque:
.data()
comunica a outros programadores lendo o código fonte que os dados não são ASCIIZ (ao invés disso, você're utilizando a string para armazenar um bloco de dados (que às vezes é'nem mesmo textual)), ou que você're passando-o para outra função que o trata como um bloco de "binário" dados. Isto pode ser uma visão crucial para garantir que outros programadores' mudanças de código continuem a tratar os dados corretamente.string
precisar fazer alguma alocação extra de memória e/ou cópia de dados para preparar o buffer terminado NUL
Como uma dica adicional, se uma função's parâmetros requer o (const
) char*
mas don't insiste em obter x.size()
, a função provavelmente precisa de uma entrada ASCIIZ, então .c_str()
é uma boa escolha (a função precisa saber onde o texto termina de alguma forma, então se ele's não é um parâmetro separado, ele só pode ser uma convenção como um comprimento-prefixo ou sentinela ou algum comprimento fixo esperado).
Como obter um ponteiro de caracteres válido mesmo após o `x' deixar o escopo ou ser modificado maisVocê'precisará copiar o conteúdo do string
x
para uma nova área de memória fora do x
. Este buffer externo pode estar em muitos lugares, como outra variável do string
ou array de caracteres, ele pode ou não ter uma vida útil diferente do x
por estar em um escopo diferente (por exemplo, namespace, global, estático, heap, memória compartilhada, arquivo mapeado de memória).
Para copiar o texto de std::string x
para um array 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<char> old_x(x.data(), x.data() + x.size()); // without the NUL
std::vector<char> 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 (e.g. 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);
Então, acima de você'já vi como obter um (const
) char*
, e como fazer uma cópia do texto independente do string
original, mas o que você pode do com ele? Um rabisco aleatório de exemplos...
string
's, como em printf("x é '%s'", x.c_str());
x
's para um buffer especificado pela sua função's caller (por exemplo strncpy(callers_buffer, callers_buffer_size, x.c_str())
), ou memória volátil utilizada para E/S do dispositivo (por exemplo for (const char* p = x.c_str(); *p; ++p) *p_device = *p;
)x
's text to an character array already containing some ASCIIZ text (e.g. strcat(other_buffer, x.c_str())
) - tenha cuidado para não ultrapassar o buffer (em muitas situações você pode precisar utilizar strncat
)const char*
ou char*
de uma função (talvez por razões históricas - cliente's utilizando sua API existente - ou para compatibilidade C você não'não quer retornar um std::string
, mas quer copiar os dados do seu string
's em algum lugar para o autor da chamada)std::string
(ex. STLport e compilador-nativo) podem passar dados como ASCIIZ para evitar conflitosUtilize o método .c_str()
para const char *
.
Você pode utilizar &mystring[0]
para obter um char *
ponteiro, mas há um par de gotcha's: você ganhou't necessariamente obter uma string terminada zero, e você ganhou't ser capaz de mudar o tamanho da string's. Você especialmente tem que ter cuidado para não adicionar caracteres depois do fim da string ou você'vai obter um buffer overrun (e provável crash).
Não havia garantia de que todos os caracteres fariam parte do mesmo buffer contíguo até C++11, mas na prática todas as implementações conhecidas de std::string
funcionavam dessa forma de qualquer maneira; veja Does "&s[0]" point to contiguous characters in a std::string?.
Note que muitas funções de membros do string
irão realocar o buffer interno e invalidar quaisquer apontadores que você possa ter salvo. É melhor utilizá-los imediatamente e depois descartar.