std :: string to char *


335

Voglio convertire una stringa std :: string in un tipo di dati char * o char [] .

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

Risultati in: "errore: impossibile convertire" std :: string "in" char "..." .

Quali metodi sono disponibili per farlo?

c++  string  char 

Risposte:


672

Non si convertirà automaticamente (grazie a dio). Dovrai utilizzare il metodo c_str()per ottenere la versione della stringa C.

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

Si noti che restituisce a const char *; non ti è permesso cambiare la stringa di tipo C restituita da c_str(). Se vuoi elaborarlo, devi prima copiarlo:

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

O nel C ++ moderno:

std::vector<char> cstr(str.c_str(), str.c_str() + str.size() + 1);

4
@Kerrek SB: Era un esempio, usava un puntatore intelligente in codice reale, o più probabilmente evitava c_strcompletamente questa follia.
orlp,

14
La risposta è voluminosa, non elegante, non locale, utilizza array grezzi e richiede attenzione alla sicurezza delle eccezioni. vectorè stato inventato proprio come un wrapper per array dinamici, quindi non utilizzarlo sembra un'opportunità mancata nel migliore dei casi e in violazione dello spirito del C ++ nel peggiore dei casi.
Kerrek SB,

21
Prima di tutto, sì, la risposta è voluminosa. Innanzitutto spiego l'errore dell'OP (pensando che std::stringsi convertirà automaticamente) e poi spiego cosa dovrebbe usare, con un esempio di codice breve. In prospettiva spiego anche alcuni effetti collaterali dell'uso di questa funzione, di cui uno è che non è possibile modificare la stringa restituita da c_str(). Vedi erroneamente i miei brevi esempi come un vero codice per la risoluzione dei problemi, che non lo è.
orlp,

8
Ho votato in negativo la risposta. Questa risposta non è davvero utile e il fatto che sia stata accettata è molto sfortunato. Questa risposta ignora completamente le buone pratiche di programmazione C ++ e la sicurezza delle eccezioni e ci sono soluzioni di gran lunga superiori, alcune delle quali sono fornite in altre risposte a questa domanda (ad esempio la risposta data da ildjarn che utilizza std::vector<char>).
James McNellis,

114
@ james-mcnellis, ho scelto questa risposta come quella corretta perché ha risposto ESATTAMENTE a quello che stavo chiedendo ... Niente di più, niente di meno. Non ho chiesto cosa pensi che dovrei fare, non ho chiesto una soluzione diversa per quello che pensi che sto facendo, non ho chiesto buone pratiche. Non hai idea di cosa sto lavorando, dove verrà implementato il mio codice e in quali condizioni. Alcuni dovrebbero imparare a leggere, comprendere le domande e rispondere a ciò che viene effettivamente chiesto. Non c'è bisogno di mettersi in mostra qui.

151

Maggiori dettagli qui e qui ma è possibile utilizzare

string str = "some string" ;
char *cstr = &str[0];

15
FWIW, nel mio libro, questa è l'unica risposta corretta alla domanda che è stata effettivamente posta. Una stringa std :: string è intrinsecamente mutevole: le persone che la stanno facendo sembrare come modificare il contenuto della stringa sono in qualche modo il lavoro del diavolo sembra mancare a questo fatto.
Jay Freeman -saurik-

2
si, questa è la risposta corretta. è sciocco che, data la frequenza d'uso, non ci sia un metodo standard per farlo, come il lockbuffer di msoft.
Erik Aronesty,

1
Ho cambiato da 0 a 0u. Perché alcuni compilatori / librerie (ci crederanno o no) si lamenteranno di alcune ambiguità quando gli avvisi vengono attivati ​​fino in fondo per il costrutto & str [0]
Erik Aronesty,

Dubito che quando lo str viene eliminato, il carattere sia reso nullo. Quindi suppongo che al puntatore char sia assegnato solo un puntatore della stringa. Quindi la conversione di stringa in carattere non è letteralmente completa. String è puntato solo su char * ma il suo valore non viene convertito. Ho ragione???
Samitha Chathuranga,

5
Si noti che questo è solo C ++ 11. Le versioni precedenti potrebbero non disporre di memoria continua o mancare del null finale
Flamefire,

39

Se avessi bisogno di una copia raw mutabile del contenuto della stringa di un c ++, allora farei questo:

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

e più tardi:

free(chr); 

Quindi perché non giocherellare con std :: vector o new [] come chiunque altro? Perché quando ho bisogno di una stringa char char * in stile C mutabile, allora perché voglio chiamare il codice C che cambia la stringa e il codice C dealloca le cose con free () e le alloca con malloc () (strdup usa malloc) . Quindi, se passo la mia stringa non elaborata a una funzione X scritta in C , potrebbe avere un vincolo sull'argomento che deve essere allocato sull'heap (ad esempio se la funzione potrebbe voler chiamare realloc sul parametro). Ma è altamente improbabile che si aspetti un argomento assegnato con (alcuni ridefiniti dall'utente) nuovo []!


Dovresti spiegare da dove strdupviene.
LF

22

(Questa risposta si applica solo a C ++ 98).

Per favore, non usare un raw char*.

std::string str = "string";
std::vector<char> chars(str.c_str(), str.c_str() + str.size() + 1u);
// use &chars[0] as a char*

1
In realtà oggi avevo solo bisogno di qualcosa del genere. Mi chiedevo, va bene dire vector<char>(str.c_str(), str.c_str() + str.size() + 1), senza assegnare il puntatore al carattere a un temporaneo?
Kerrek SB,

1
@Kerrek: Sì, il valore di ritorno di std::basic_string<>::c_str()è valido fino a quando non stringviene modificato o distrutto. Ciò implica anche che restituisce lo stesso valore nelle chiamate successive purché stringnon venga modificato.
ildjarn,

2
@friendzis: vectorin questo modo non vi è alcun sovraccarico di velocità o spazio . E se si scrivesse un codice sicuro per le eccezioni senza un meccanismo RAII (ovvero usando puntatori non elaborati), la complessità del codice sarebbe molto più elevata di questo semplice one-liner.
ildjarn,

7
È un mito che vectorha un'enorme quantità di costi generali e complessità. Se il tuo requisito è che tu abbia un array di caratteri mutabile , in realtà un vettore di caratteri è praticamente il wrapper C ++ ideale. Se il tuo requisito in realtà richiede solo un puntatore const-char, allora basta usare c_str()e il gioco è fatto.
Kerrek SB,


14
  • Se vuoi solo una stringa in stile C che rappresenti lo stesso contenuto:

    char const* ca = str.c_str();
  • Se si desidera una stringa in stile C con nuovi contenuti, un modo (dato che non si conosce la dimensione della stringa in fase di compilazione) è l'allocazione dinamica:

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

    Non dimenticarlo delete[]più tardi.

  • Se si desidera invece un array di lunghezza limitata allocato staticamente:

    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::stringnon si converte implicitamente in questi tipi per la semplice ragione che la necessità di farlo è di solito un odore di design. Assicurati di averne davvero bisogno.

Se hai sicuramente bisogno di un char*, il modo migliore è probabilmente:

vector<char> v(str.begin(), str.end());
char* ca = &v[0]; // pointer to start of vector

1
Perché &str.front(), &str.back()(che non sono presenti in C ++ 03) anziché i più comuni str.begin()e str.end()?
Armen Tsirunyan,

1
che dire str.begin(), o addirittura std::begin(str), simile a un iteratore? Non credo stringabbia alcun obbligo di essere nella memoria contigua come vector, o no ?
xtofl,

1
@xtofl: ho già modificato quelli in. E sì, a partire da C ++ 11 c'è un obbligo; questo era implicito in C ++ 03.
Razze di leggerezza in orbita

@xtofl: non in C ++ 03. In C ++ 11 abbiamo quella garanzia, insieme alle funzioni front () e back (), che sono state usate in modo improprio nella risposta originale
Armen Tsirunyan

1
@Tomalak: sono stati abusati del necessario &back() + 1, non&back()
Armen Tsirunyan,

12

Sarebbe meglio come un commento sulla risposta di bobobobo, ma non ho il rappresentante per questo. Compie la stessa cosa ma con pratiche migliori.

Anche se le altre risposte sono utili, se mai hai bisogno di convertire std::stringa char*esplicitamente, senza const, const_castè tuo amico.

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

Nota che questo non ti darà una copia dei dati; ti darà un puntatore alla stringa. Pertanto, se si modifica un elemento di chr, si modificherà str.


6

Supponendo che hai solo bisogno di una stringa in stile C per passare come input:

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

4

Per essere rigorosamente pedanti, non è possibile "convertire una stringa std :: string in un tipo di dati char * o char []".

Come hanno mostrato le altre risposte, è possibile copiare il contenuto di std :: string in un array di caratteri oppure creare un carattere const * nel contenuto di std :: string in modo che sia possibile accedervi in ​​uno "stile C" .

Se stai provando a cambiare il contenuto dello std :: string, il tipo std :: string ha tutti i metodi per fare qualsiasi cosa tu possa aver bisogno di farci.

Se stai provando a passarlo a qualche funzione che richiede un carattere *, c'è std :: string :: c_str ().


4

Ecco un'altra versione robusta di 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

+1 per verificare che la stringa sia vuota. Vorrei anche aggiungere un segno di spunta per assicurarsi che la stringa sia terminata con zero: if (str[str.length()-1] != 0) str.push_back(0)
GaspardP

4

Conversione in stile 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")

Mi piace come il cast di char * elimini la const dall'output di c_str, penso che il motivo per cui c_str restituisca const char * sia quello di eliminare potenziali problemi di accesso alla memoria, fornendo una versione di sola lettura della cosa. l'OP vuole avere un carattere *, ma penso che potrebbe essere meglio servito da const char * output di c_str, dato che è più sicuro, e le funzioni che prendono char * di solito prendono anche const char * (supponendo che le funzioni non lo facciano fare qualcosa come cambiare i loro input, che in generale non dovrebbero).
Felipe Valdes,

3

Per completezza, non dimenticare std::string::copy().

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

str.copy(chrs, MAX);

std::string::copy()non termina NUL. Se è necessario garantire un terminatore NUL per l'uso nelle funzioni di stringa C:

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

memset(chrs, '\0', MAX);
str.copy(chrs, MAX-1);

3

Puoi farlo usando iteratore.

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

In bocca al lupo.


3

Una versione sicura della risposta char * di orlp usando unique_ptr:

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

3

Per ottenere un const char *da un std::stringuso la c_str()funzione membro:

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

Per ottenere un non const char *da un std::stringè possibile utilizzare la data()funzione membro che restituisce un puntatore non const dal C ++ 17:

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

Per le versioni precedenti della lingua, è possibile utilizzare la costruzione di intervalli per copiare la stringa in un vettore da cui è possibile ottenere un puntatore non const:

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

Ma attenzione che questo non ti permetterà di modificare la stringa contenuta in str, solo i dati della copia possono essere modificati in questo modo. Si noti che è particolarmente importante nelle versioni precedenti del linguaggio utilizzare c_str()qui perché all'epoca std::stringnon era garantito che venisse annullato fino a quando non c_str()veniva chiamato.


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

2

In alternativa, è possibile utilizzare i vettori per ottenere un carattere scrivibile * come mostrato di seguito;

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

Ciò allocherà nuova memoria per il vettore e quindi copierà ogni carattere. std :: string è già un contenitore, potresti anche push_back (0) nella tua stringa e fare & str [0]
GaspardP

1

Questo funzionerà anche

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;  
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.