std :: string para char *

335

Quero converter um std :: string em um tipo de dados char * ou char [] .

std::string str = "string";
char* chr = str;

Resultados em: “erro: não é possível converter 'std :: string' em 'char' ...” .

Quais métodos existem para fazer isso?

Mario
fonte

Respostas:

671

Não será convertido automaticamente (graças a Deus). Você precisará usar o método c_str()para obter a versão da string C.

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

Observe que ele retorna a const char *; você não tem permissão para alterar a string do estilo C retornada por c_str(). Se você quiser processá-lo, precisará copiá-lo primeiro:

std::string str = "string";
char *cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
// do stuff
delete [] cstr;

Ou no C ++ moderno:

std::vector<char> cstr(str.c_str(), str.c_str() + str.size() + 1);
orlp
fonte
4
@ Kerrek SB: Era um exemplo, usaria um ponteiro inteligente em código real ou, mais provavelmente, evitaria essa c_strloucura completamente.
orlp 8/09/11
14
A resposta é volumosa, deselegante, não local, usa matrizes brutas e requer atenção à segurança de exceção. vectorfoi inventado precisamente como um invólucro para matrizes dinâmicas; portanto, não usá-lo parece uma oportunidade perdida na melhor das hipóteses, e violando o espírito do C ++ na pior das hipóteses.
Kerrek SB
21
Primeiro de tudo, sim, a resposta é volumosa. Primeiro, explico o erro do OP (pensando que std::stringseria convertido automaticamente) e depois explico o que ele deve usar, com um pequeno exemplo de código. Pensando no futuro, também explico alguns efeitos colaterais do uso dessa função, dos quais um é que você não pode editar a string retornada por c_str(). Por engano, você vê meus pequenos exemplos como um código real de solução de problemas, o que não é.
orlp 8/09/11
8
Eu diminuí a votação. Essa resposta não é realmente útil e o fato de ter sido aceita é muito lamentável. Esta resposta desconsidera completamente as boas práticas de programação C ++ e a segurança de exceções e existem soluções muito superiores, algumas das quais são fornecidas em outras respostas a esta pergunta (por exemplo, a resposta dada por ildjarn que usa std::vector<char>).
James McNellis 08/09/11
114
@ James-McNellis, eu escolhi esta resposta como a correta, porque respondeu exatamente o que eu estava pedindo ... Nem mais, nem menos. Não pedi o que você acha que deveria fazer, não pedi uma solução diferente para o que você pensa que estou fazendo, não pedi boas práticas. Você não tem idéia no que estou trabalhando, onde meu código será implementado e sob quais condições. Alguns devem aprender a ler, entender perguntas e responder ao que realmente está sendo solicitado. Não há necessidade de mostrar aqui.
150

Mais detalhes aqui e aqui, mas você pode usar

string str = "some string" ;
char *cstr = &str[0];
bobobobo
fonte
15
FWIW, no meu livro, esta é a única resposta correta para a pergunta que realmente foi feita. Um std :: string é inerentemente mutável: as pessoas que estão fazendo parecer modificar o conteúdo da string são de alguma forma que o trabalho do diabo parece estar perdendo esse fato.
precisa saber é o seguinte
2
Sim, esta é a resposta correta. é bobagem que, dada a frequência de uso, não exista um método padrão para fazer isso, como o lockbuffer da msoft.
Erik Aronesty
11
Eu mudei 0 para 0u. Porque alguns compiladores / bibliotecas (acredite ou não) se queixam de alguma ambigüidade quando os avisos são virou todo o caminho para o & str [0] construção
Erik Aronesty
Eu duvido que quando o str é excluído, o char cstr é tornado nulo. Então, acho que aqui apenas um ponteiro da string é atribuído ao ponteiro char. Portanto, a conversão de string em char não está literalmente completa. String só é apontada para char *, mas seu valor não é convertido. Estou correcto???
Samitha Chathuranga
5
Observe que isso é apenas C ++ 11. As versões anteriores podem não ter o armazenamento contínuo ou está faltando o nulo de terminação
Flamefire
40

Se eu precisar de uma cópia bruta mutável do conteúdo de uma string do c ++, faça o seguinte:

std::string str = "string";
char* chr = strdup(str.c_str());

e depois:

free(chr); 

Então, por que não brinco com std :: vector ou new [] como qualquer outra pessoa? Porque quando eu preciso de uma seqüência de caracteres char * mutável do estilo C, porque desejo chamar o código C, que altera a sequência e o código C desaloca as coisas com free () e aloca com malloc () (strdup usa malloc) . Portanto, se eu passar minha string bruta para alguma função X escrita em C , pode haver uma restrição no argumento de que ela deve ser alocada no heap (por exemplo, se a função desejar chamar realloc no parâmetro). Mas é altamente improvável que ele espere um argumento alocado com (alguns redefinidos pelo usuário) new []!

Mainframe nórdico
fonte
Você deve explicar de onde strdupé.
LF
22

(Esta resposta se aplica apenas ao C ++ 98.)

Por favor, não use cru char*.

std::string str = "string";
std::vector<char> chars(str.c_str(), str.c_str() + str.size() + 1u);
// use &chars[0] as a char*
ildjarn
fonte
11
Na verdade, eu só precisava de algo assim hoje cedo. Eu queria saber, é certo dizer vector<char>(str.c_str(), str.c_str() + str.size() + 1), sem atribuir o ponteiro de char a um temporário?
Kerrek SB
11
@ Kerrek: Sim, o valor retornado std::basic_string<>::c_str()é válido até que stringseja alterado ou destruído. Isso também implica que ele retorna o mesmo valor em chamadas subseqüentes, desde que stringnão seja modificado.
precisa saber é o seguinte
2
@friendzis: Não há velocidade ou espaço em sobrecarga usando vectordessa maneira. E se alguém escrevesse código com exceção de segurança sem um mecanismo RAII (ou seja, usando ponteiros brutos), a complexidade do código seria muito maior do que essa simples linha.
Jarjarjarn 08/09
7
É um mito que vectorpossui uma enorme quantidade de sobrecarga e complexidade. Se o seu requisito é que você tenha uma matriz de caracteres mutável , na verdade um vetor de caracteres é praticamente o wrapper C ++ ideal. Se o seu requisito realmente exige apenas um ponteiro const-char, basta usar c_str()e pronto.
Kerrek SB
3
@ildjarn: Na verdade, basicamente era .
Lightness Races in Orbit
15
  • Se você deseja apenas uma string no estilo C representando o mesmo conteúdo:

    char const* ca = str.c_str();
  • Se você deseja uma string no estilo C com novos conteúdos, uma maneira (desde que você não saiba o tamanho da string no tempo de compilação) é a alocação dinâmica:

    char* ca = new char[str.size()+1];
    std::copy(str.begin(), str.end(), ca);
    ca[str.size()] = '\0';

    Não esqueça delete[]disso mais tarde.

  • Se você deseja uma matriz de tamanho limitado alocada estaticamente, em vez disso:

    size_t const MAX = 80; // maximum number of chars
    char ca[MAX] = {};
    std::copy(str.begin(), (str.size() >= MAX ? str.begin() + MAX : str.end()), ca);

std::stringnão se converte implicitamente nesses tipos pelo simples motivo de que a necessidade de fazer isso geralmente é um cheiro de design. Certifique-se de que você realmente precisa.

Se você definitivamente precisa de um char*, a melhor maneira é provavelmente:

vector<char> v(str.begin(), str.end());
char* ca = &v[0]; // pointer to start of vector
Raças de leveza em órbita
fonte
11
Por &str.front(), &str.back()que (que não estão presentes no C ++ 03) em vez dos mais comuns str.begin()e str.end()?
Armen Tsirunyan
11
o que dizer str.begin(), ou mesmo std::begin(str), iterator-like? Eu não acredito que stringtenha qualquer obrigação de estar na memória contígua vector, ou tem?
Xtofl
11
@xtofl: Eu já editei aqueles em. E sim, a partir do C ++ 11 existe uma obrigação; isso estava implícito no C ++ 03.
Lightness Races em órbita
@xtofl: Não está em C ++ 03. Em C ++ 11 temos essa garantia, juntamente com a frente () e back () funções, que foram mal utilizados na resposta original de qualquer maneira
Armen Tsirunyan
11
@Tomalak: Eles foram mal utilizados em que você precisava &back() + 1, não&back()
Armen Tsirunyan
12

Isso seria melhor como um comentário sobre a resposta de bobobobo, mas não tenho o representante para isso. Ele realiza a mesma coisa, mas com melhores práticas.

Embora as outras respostas sejam úteis, se você precisar converter std::stringpara char*explicitamente sem const, const_casté seu amigo.

std::string str = "string";
char* chr = const_cast<char*>(str.c_str());

Observe que isso não fornecerá uma cópia dos dados; isso lhe dará um ponteiro para a string. Assim, se você modificar um elemento de chr, modificará str.

sem pêlo
fonte
7

Supondo que você só precise de uma string no estilo C para passar como entrada:

std::string str = "string";
const char* chr = str.c_str();
Mark B
fonte
5

Para ser estritamente pedante, você não pode "converter uma std :: string em um tipo de dados char * ou char []".

Como as outras respostas mostraram, você pode copiar o conteúdo do std :: string para uma matriz char ou criar um const char * para o conteúdo do std :: string, para que você possa acessá-lo no "estilo C" .

Se você está tentando alterar o conteúdo do std :: string, o tipo std :: string possui todos os métodos para fazer qualquer coisa que você possa precisar fazer.

Se você está tentando passar para alguma função que aceita um caractere *, há std :: string :: c_str ().

Rob K
fonte
4

Por uma questão de completude, não esqueça std::string::copy().

std::string str = "string";
const size_t MAX = 80;
char chrs[MAX];

str.copy(chrs, MAX);

std::string::copy()NUL não termina. Se você precisar garantir um terminador NUL para uso nas funções da string C:

std::string str = "string";
const size_t MAX = 80;
char chrs[MAX];

memset(chrs, '\0', MAX);
str.copy(chrs, MAX-1);
Jeffery Thomas
fonte
4

Aqui está uma versão mais robusta do Protocol Buffer

char* string_as_array(string* str)
{
    return str->empty() ? NULL : &*str->begin();
}

// test codes
std::string mystr("you are here");
char* pstr = string_as_array(&mystr);
cout << pstr << endl; // you are here
zangw
fonte
+1 para verificar se a sequência está vazia. Gostaria de acrescentar também uma verificação para certificar-se de que a cadeia é nula terminada: if (str[str.length()-1] != 0) str.push_back(0)
GaspardP
4

Conversão no estilo OOP

converter.hpp

class StringConverter {
    public: static char * strToChar(std::string str);
};

converter.cpp

char * StringConverter::strToChar(std::string str)
{
    return (char*)str.c_str();
}

uso

StringConverter::strToChar("converted string")
Patryk Merchelski
fonte
Eu gosto de como o elenco para char * elimina a const da saída de c_str, acho que a razão pela qual c_str retorna const char * é eliminar possíveis problemas de acesso à memória, fornecendo uma versão somente leitura da coisa. o OP quer ter um char *, mas acho que ele pode ser melhor atendido pela const char * output de c_str, já que isso é mais seguro, e as funções que aceitam char * geralmente também aceitam char * (assumindo que as funções não faça qualquer coisa como alterar suas entradas, o que geralmente não deveria).
Felipe Valdes
3
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
cegprakash
fonte
3

Como alternativa, você pode usar vetores para obter um caractere gravável *, conforme demonstrado abaixo;

//this handles memory manipulations and is more convenient
string str;
vector <char> writable (str.begin (), str.end) ;
writable .push_back ('\0'); 
char* cstring = &writable[0] //or &*writable.begin () 

//Goodluck  

fonte
Isso alocará nova memória para o vetor e copiará cada caractere. std :: string já é um recipiente, assim como você pode push_back (0) para a cadeia e fazer & str [0]
GaspardP
3

Você pode fazer isso usando o iterador.

std::string str = "string";
std::string::iterator p=str.begin();
char* chr = &(*p);

Boa sorte.

TS.PARK
fonte
3

Uma versão segura da resposta char * do orlp usando unique_ptr:

std::string str = "string";
auto cstr = std::make_unique<char[]>(str.length() + 1);
strcpy(cstr.get(), str.c_str());
Enhex
fonte
3

Para obter um const char *de um std::stringuso, a c_str()função de membro:

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

Para obter um não-const char *de um, std::stringvocê pode usar a data()função de membro que retorna um ponteiro não-const desde C ++ 17:

std::string str = "string";
char* chr = str.data();

Para versões mais antigas do idioma, você pode usar a construção de intervalo para copiar a sequência em um vetor do qual um ponteiro não-const pode ser obtido:

std::string str = "string";
std::vector<char> str_copy(str.c_str(), str.c_str() + str.size() + 1);
char* chr = str_copy.data();

Mas lembre-se de que isso não permitirá que você modifique a string contida str, apenas os dados da cópia podem ser alterados dessa maneira. Observe que é especialmente importante nas versões mais antigas do idioma usar c_str()aqui, porque naquela época std::stringnão havia garantia de que o nulo terminasse até que c_str()fosse chamado.

François Andrieux
fonte
2

Isso também vai funcionar

std::string s;
std::cout<<"Enter the String";
std::getline(std::cin, s);
char *a=new char[s.size()+1];
a[s.size()]=0;
memcpy(a,s.c_str(),s.size());
std::cout<<a;  
Genocide_Hoax
fonte