std :: string to char *

335

Ich möchte einen std :: string in einen Datentyp char * oder char [] konvertieren .

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

Ergebnisse in: "Fehler: 'std :: string' kann nicht in 'char' konvertiert werden ..." .

Welche Methoden gibt es dafür?

Mario
quelle

Antworten:

671

Es wird nicht automatisch konvertiert (Gott sei Dank). Sie müssen die Methode verwenden c_str(), um die C-String-Version zu erhalten.

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

Beachten Sie, dass es a zurückgibt const char *; Sie dürfen die von zurückgegebene Zeichenfolge im C-Stil nicht ändern c_str(). Wenn Sie es verarbeiten möchten, müssen Sie es zuerst kopieren:

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

Oder in modernem C ++:

std::vector<char> cstr(str.c_str(), str.c_str() + str.size() + 1);
orlp
quelle
4
@ Kerrek SB: Es war ein Beispiel, würde einen intelligenten Zeiger in echtem Code verwenden oder diesen c_strWahnsinn eher vollständig vermeiden .
Orlp
14
Die Antwort ist sperrig, unelegant, nicht lokal, verwendet Raw-Arrays und erfordert die Beachtung der Ausnahmesicherheit. vectorwurde genau als Wrapper für dynamische Arrays erfunden, daher scheint es im besten Fall eine verpasste Gelegenheit zu sein und im schlimmsten Fall gegen den Geist von C ++ zu verstoßen.
Kerrek SB
21
Zuallererst, ja, die Antwort ist sperrig. Zuerst erkläre ich den Fehler des OP (ich denke, das std::stringwürde sich automatisch konvertieren) und dann erkläre ich anhand eines kurzen Codebeispiels, was er verwenden sollte. Wenn ich nach vorne denke, erkläre ich auch einige Nebenwirkungen der Verwendung dieser Funktion, von denen eine darin besteht, dass Sie die von zurückgegebene Zeichenfolge möglicherweise nicht bearbeiten c_str(). Sie sehen meine kurzen Beispiele fälschlicherweise als echten Code zur Problemlösung, was es nicht ist.
Orlp
8
Ich habe die Antwort abgelehnt. Diese Antwort ist in der Tat nicht nützlich und die Tatsache, dass sie akzeptiert wurde, ist äußerst bedauerlich. Diese Antwort ignoriert gute C ++ - Programmierpraktiken und Ausnahmesicherheit vollständig und es gibt weit überlegene Lösungen, von denen einige in anderen Antworten auf diese Frage angegeben sind (z. B. die Antwort von ildjarn, die verwendet std::vector<char>).
James McNellis
114
@ james-mcnellis, ich habe diese Antwort als die richtige ausgewählt, weil sie genau das beantwortet hat, wonach ich gefragt habe ... Nicht mehr und nicht weniger. Ich habe nicht gefragt, was Sie denken, dass ich tun soll, ich habe nicht nach einer anderen Lösung für das gefragt, was Sie denken, dass ich tue, ich habe nicht nach guten Praktiken gefragt. Sie haben keine Ahnung, woran ich arbeite, wo und unter welchen Bedingungen mein Code implementiert wird. Einige sollten lernen zu lesen, Fragen zu verstehen und zu beantworten, was tatsächlich gestellt wird. Hier muss man nicht angeben.
147

Weitere Details hier und hier, aber Sie können verwenden

string str = "some string" ;
char *cstr = &str[0];
Bobobobo
quelle
15
FWIW, in meinem Buch ist dies die einzig richtige Antwort auf die Frage, die tatsächlich gestellt wurde. Ein std :: string ist von Natur aus veränderlich: Menschen, die es so klingen lassen, als würden sie den Inhalt des Strings ändern, scheinen der Arbeit des Teufels diese Tatsache zu fehlen.
Jay Freeman -saurik-
2
Ja, das ist die richtige Antwort. Es ist albern, dass es angesichts der Häufigkeit der Verwendung keine Standardmethode gibt, wie den Lockbuffer von msoft.
Erik Aronesty
1
Ich habe 0 zu 0u geändert. Weil einige Compiler / Bibliotheken (ob Sie es glauben oder nicht) sich über Unklarheiten beschweren, wenn Warnungen für das Konstrukt & str [0]
vollständig aktiviert werden
Ich bezweifle, dass beim Löschen des Str das Zeichen cstr auf null gesetzt wird. Ich denke, hier wird dem Zeichenzeiger nur ein Zeiger der Zeichenfolge zugewiesen. Die Konvertierung von Zeichenfolgen in Zeichen ist also nicht buchstäblich abgeschlossen. Der String zeigt nur auf char *, aber sein Wert wird nicht konvertiert. Hab ich recht???
Samitha Chathuranga
5
Beachten Sie, dass dies nur C ++ 11 ist. Frühere Versionen haben möglicherweise keinen kontinuierlichen Speicher oder es fehlt die abschließende Null
Flamefire
40

Wenn ich eine veränderbare Rohkopie des Inhalts eines C ++ - Strings benötigen würde, würde ich Folgendes tun:

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

und später:

free(chr); 

Warum spiele ich nicht wie jeder andere mit std :: vector oder new []? Denn wenn ich eine veränderbare rohe char * -String-Zeichenfolge im C-Stil benötige, möchte ich C-Code aufrufen, der die Zeichenfolge ändert, und C-Code die Zuordnung von Sachen mit free () und die Zuweisung von malloc () aufheben (strdup verwendet malloc) . Wenn ich also meine Rohzeichenfolge an eine in C geschriebene Funktion X übergebe , hat dies möglicherweise eine Einschränkung für das Argument, dass sie auf dem Heap zugewiesen werden muss (z. B. wenn die Funktion möglicherweise Realloc für den Parameter aufrufen möchte). Es ist jedoch höchst unwahrscheinlich, dass ein Argument erwartet wird, das mit (einigen vom Benutzer neu definierten) neuen [] zugewiesen wird!

Nordischer Mainframe
quelle
Sie sollten erklären, woher strdupkommt.
LF
22

(Diese Antwort gilt nur für C ++ 98.)

Bitte verwenden Sie keine rohen 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
quelle
1
Ich brauchte heute eigentlich nur so etwas. Ich habe mich gefragt, ob es in Ordnung ist zu sagen vector<char>(str.c_str(), str.c_str() + str.size() + 1), ohne den Zeichenzeiger einem temporären zuzuweisen.
Kerrek SB
1
@Kerrek: Ja, der Rückgabewert von std::basic_string<>::c_str()ist gültig, bis der stringgeändert oder zerstört wird. Dies bedeutet auch, dass bei nachfolgenden Aufrufen derselbe Wert zurückgegeben wird, solange der stringnicht geändert wird.
ildjarn
2
@friendzis: Auf vectordiese Weise wird weder Geschwindigkeit noch Platz benötigt . Und wenn man schreiben würde Ausnahme sicher ohne RAII Mechanismus Code (dh unter Verwendung von rohen Zeigern), würde die Komplexität des Codes viel höher sein als dieser einfache Einzeiler.
ildjarn
7
Es ist ein Mythos, vectorder viel Aufwand und Komplexität mit sich bringt. Wenn Sie ein veränderbares Zeichenarray benötigen, ist ein Zeichenvektor tatsächlich der ideale C ++ - Wrapper. Wenn Ihre Anforderung tatsächlich nur einen const-char-Zeiger erfordert, verwenden c_str()Sie einfach und Sie sind fertig.
Kerrek SB
3
@ildjarn: Eigentlich war es im Grunde .
Leichtigkeitsrennen im Orbit
15
  • Wenn Sie nur eine Zeichenfolge im C-Stil möchten, die denselben Inhalt darstellt:

    char const* ca = str.c_str();
  • Wenn Sie eine Zeichenfolge im C-Stil mit neuem Inhalt möchten , besteht eine Möglichkeit (da Sie die Zeichenfolgengröße zur Kompilierungszeit nicht kennen) in der dynamischen Zuweisung:

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

    Vergiss delete[]es später nicht.

  • Wenn Sie stattdessen ein statisch zugewiesenes Array mit begrenzter Länge möchten:

    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::stringKonvertiert nicht implizit in diese Typen aus dem einfachen Grund, dass dies normalerweise ein Designgeruch ist. Stellen Sie sicher, dass Sie es wirklich brauchen.

Wenn Sie definitiv eine brauchen char*, ist der beste Weg wahrscheinlich:

vector<char> v(str.begin(), str.end());
char* ca = &v[0]; // pointer to start of vector
Leichtigkeitsrennen im Orbit
quelle
1
Warum &str.front(), &str.back()(die in C ++ 03 nicht vorhanden sind) statt der häufigeren str.begin()und str.end()?
Armen Tsirunyan
1
Was str.begin()ist mit oder sogar std::begin(str)iteratorartig? Ich glaube nicht, dass stringes eine Verpflichtung gibt, in zusammenhängender Erinnerung zu sein vector, oder?
xtofl
1
@xtofl: Ich habe diese bereits bearbeitet. Und ja, ab C ++ 11 gibt es eine Verpflichtung; Dies war in C ++ 03 implizit.
Leichtigkeitsrennen im Orbit
@xtofl: Nicht in C ++ 03. In C ++ 11 haben wir diese Garantie, zusammen mit den Funktionen front () und back (), die in der ursprünglichen Antwort sowieso missbraucht wurden
Armen Tsirunyan
1
@Tomalak: Sie wurden in missbraucht , dass man benötigt &back() + 1, nicht&back()
Armen Tsirunyan
12

Dies wäre besser als Kommentar zu Bobobobos Antwort, aber ich habe keinen Repräsentanten dafür. Es erreicht das Gleiche, aber mit besseren Praktiken.

Obwohl die anderen Antworten nützlich sind, wenn Sie jemals konvertieren müssen , std::stringum char*explizit ohne const, const_castist dein Freund.

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

Beachten Sie, dass dies nicht eine Kopie der Daten geben; Sie erhalten einen Zeiger auf die Zeichenfolge. Wenn Sie also ein Element von chrändern, ändern Sie es str.

haarloser Bär
quelle
7

Angenommen, Sie benötigen nur eine Zeichenfolge im C-Stil, um sie als Eingabe zu übergeben:

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

Um streng pedantisch zu sein, können Sie "einen std :: string nicht in einen char * - oder char [] -Datentyp konvertieren".

Wie die anderen Antworten gezeigt haben, können Sie den Inhalt des std :: string in ein char-Array kopieren oder ein const char * für den Inhalt des std :: string erstellen, damit Sie in einem "C-Stil" darauf zugreifen können. .

Wenn Sie versuchen, den Inhalt des std :: string zu ändern, verfügt der std :: string-Typ über alle Methoden, um alles zu tun, was Sie möglicherweise tun müssen.

Wenn Sie versuchen, es an eine Funktion zu übergeben, die ein Zeichen * akzeptiert, gibt es std :: string :: c_str ().

Rob K.
quelle
4

Der Vollständigkeit halber nicht vergessen std::string::copy().

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

str.copy(chrs, MAX);

std::string::copy()beendet NUL nicht. Wenn Sie einen NUL-Terminator für die Verwendung in C-String-Funktionen sicherstellen müssen:

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

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

Hier ist eine weitere robuste Version von 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
quelle
+1, um zu überprüfen, ob die Zeichenfolge leer ist. Ich würde auch eine Überprüfung hinzufügen, um sicherzustellen, dass die Zeichenfolge Null beendet ist: if (str[str.length()-1] != 0) str.push_back(0)
GaspardP
4

Konvertierung im OOP-Stil

converter.hpp

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

converter.cpp

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

Verwendungszweck

StringConverter::strToChar("converted string")
Patryk Merchelski
quelle
Mir gefällt, wie die Umwandlung in char * die Konstante aus der Ausgabe von c_str entfernt. Ich denke, der Grund, warum c_str const char * zurückgibt, besteht darin, potenzielle Speicherzugriffsprobleme zu beseitigen, indem eine schreibgeschützte Version der Sache bereitgestellt wird. Das OP möchte ein Zeichen * haben, aber ich denke, er könnte stattdessen besser durch die Ausgabe von const char * von c_str bedient werden, da dies sicherer ist und Funktionen, die char * annehmen, normalerweise auch const char * annehmen (vorausgesetzt, Funktionen tun dies nicht Machen Sie etwas wie das Ändern ihrer Eingaben, was sie im Allgemeinen nicht tun sollten.
Felipe Valdes
3
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
Cegprakash
quelle
3

Alternativ können Sie Vektoren verwenden, um ein beschreibbares Zeichen * zu erhalten, wie unten gezeigt.

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

quelle
Dadurch wird dem Vektor neuer Speicher zugewiesen und anschließend jedes Zeichen kopiert. std :: string ist bereits ein Container, Sie können genauso gut push_back (0) zu Ihrem String drücken und & str [0]
GaspardP
3

Sie können es mit dem Iterator machen.

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

Viel Glück.

TS.PARK
quelle
3

Eine sichere Version von orlps char * Antwort mit unique_ptr:

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

Um eine const char *von einem zu erhalten, std::stringverwenden Sie die c_str()Member-Funktion:

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

Um eine Nicht-Konstante char *von einer zu erhalten std::string, können Sie die Elementfunktion verwenden, die data()seit C ++ 17 einen Nicht-Konstanten-Zeiger zurückgibt:

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

Bei älteren Versionen der Sprache können Sie die Zeichenfolge mithilfe der Bereichskonstruktion in einen Vektor kopieren, aus dem ein nicht konstanter Zeiger abgerufen werden kann:

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

Beachten Sie jedoch, dass Sie dadurch die darin enthaltene Zeichenfolge nicht ändern strkönnen. Nur die Daten der Kopie können auf diese Weise geändert werden. Beachten Sie, dass es in älteren Versionen der Sprache besonders wichtig ist, diese zu verwenden c_str(), da damals std::stringnicht garantiert wurde, dass sie bis c_str()zum Aufruf mit Null beendet wird .

François Andrieux
quelle
2

Dies wird auch funktionieren

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
quelle