Ich habe ein std::vector<std::string> die ich für a verwenden muss C Argument der Funktion, das lautet char* foo. Ich habe gesehen, wie man a umwandelt std::string zu char*. Als Neuling bei C++ich versuche herauszufinden, wie diese Konvertierung für jedes Element des Vektors durchgeführt und erzeugt wird char* Reihe.
Ich habe mehrere eng verwandte SO-Fragen gesehen, aber die meisten scheinen Wege zu veranschaulichen, wie man in die andere Richtung gehen und etwas erschaffen kann std::vector<std::string>.
Was ist die genaue C-Schnittstelle. Wir können verschiedene Dinge tun, je nachdem, wo sich die const befinden und wie die Funktion den Speicher während der Verwendung behandelt (C-Funktionen können unangenehme Dinge tun, wie z. B. den Aufruf von realloc).
– Martin York
13. August 2011 um 6:03 Uhr
Model* ModelInitialize (char *fnames, int nterms)
– Christopher DuBois
13. August 2011 um 6:14 Uhr
Diese Funktion akzeptiert char*nicht char** wie in deiner frage. Welches ist es?
– Luc Danton
13. August 2011 um 6:39 Uhr
verkohlen*. Sorry für die Verwirrung. Ich habe versehentlich eine Funktion betrachtet, die char** fnames als Argument akzeptiert und später ModelInitialize aufruft.
– Christopher DuBois
13. August 2011 um 6:46 Uhr
Die Funktionssignatur enthält eindeutig nicht genügend Informationen, um die richtige Vorgehensweise zu bestimmen. Ist Eigentum an fnames übertragen in ModelInitialize? (wenn ja: wie muss er zugeordnet worden sein?) Ist der aufrufende Code dazu gedacht delete, free oder anderweitig freigeben Model zurückgekehrt von ModelInitialize? (wenn ja: wie muss es freigegeben werden?) Muss fnames ein nullterminierter String sein? Auf welche Weise evtl fnames modifiziert sein?
Sie können verwenden &vc[0] wo immer Sie brauchen char**.
Beachten Sie, dass da wir verwenden new Speicher für jeden zuzuweisen std::string (in convert Funktion), müssen wir am Ende den Speicher freigeben. Dies gibt Ihnen die Flexibilität, den Vektor zu ändern vs; du kannst push_back Wenn Sie weitere Zeichenfolgen hinzufügen möchten, löschen Sie die vorhandene aus vsund vc (dh vector<char*> bleibt gültig!
Aber wenn Sie diese Flexibilität nicht wollen, dann können Sie diese nutzen convert Funktion:
Und du musst dich ändern std::vector<char*> zu std::vector<const char*>.
Jetzt nach der Transformation, wenn Sie sich ändern vs durch Einfügen neuer Zeichenfolgen oder durch Löschen der alten daraus, dann alle char* in vc könnte ungültig werden. Das ist ein wichtiger Punkt. Ein weiterer wichtiger Punkt ist, dass Sie es nicht verwenden müssen delete vc[i] in Ihrem Code mehr.
Kurze Frage: Warum ist das Löschen [] vc-Teil erforderlich, wenn wir einen std::vector verwenden?
– Christopher DuBois
13. August 2011 um 6:51 Uhr
@Christopher: Weil wir verwenden new Speicher zuzuweisen für char*deshalb machen wir delete vc[i]. Aber wir weisen keinen Speicher für zu char**daher tun wir es nicht delete vc.
– Nawaz
13. August 2011 um 7:04 Uhr
Dieser Code leckt, wenn das neue in convert wirft. Es wäre viel besser, a zu verwenden std::vector<char>.
– Mankarse
13. August 2011 um 7:32 Uhr
@Christopher: Siehe meine Antwort. Jetzt hat es mehr Erklärung.
– Nawaz
13. August 2011 um 7:36 Uhr
@Mankarse: std::vector<char> wo? In Konvertierungsfunktion? Lokale Variable?
– Nawaz
13. August 2011 um 7:40 Uhr
Das Beste, was Sie tun können, ist ein zuzuweisen std::vector von const char* die gleiche Größe wie Ihr Vektor. Gehen Sie dann durch jedes Element des Vektors und rufen Sie c_str() um das String-Array zu erhalten und das entsprechende Element des Arrays zu speichern. Dann können Sie den Zeiger auf das erste Element dieses Vektors an die betreffende Funktion übergeben.
Der Code würde so aussehen:
std::vector<const char *> cStrArray;
cStrArray.reserve(origVector.size());
for(int index = 0; index < origVector.size(); ++index)
{
cStrArray.push_back(origVector[index].c_str());
}
//NO RESIZING OF origVector!!!!
SomeCFunction(&cStrArray[0], cStrArray.size());
Beachten Sie, dass Sie kann nicht Ermöglichen Sie es, dass der ursprüngliche Vektor der Zeichenfolgen zwischen dem Abrufen der Größe geändert wird const char*s aus der std::stringsund die Zeit, zu der Sie die C-Funktion aufrufen.
Gibt c_str() kein const char zurück? Wird das ein Problem sein, wenn ich nur ein Zeichen* brauche? (Ich habe die genaue Schnittstelle in die Kommentare aufgenommen.)
– Christopher DuBois
13. August 2011 um 6:16 Uhr
Sie könnten auch std::vectorcStrArray( origVector.size()+1, NULL); und dann im Iterator cStrArray verwenden[i]=ursprünglicher Vektor[i].c_str(); Dies kann bei Funktionen wie execv() helfen. Aber wie der obige Hinweis sagt, könnten wir mehr Informationen über ModelInitialize verwenden.
– Don hell
14. Juli 2012 um 21:44 Uhr
GWW
Das sollte funktionieren:
char ** arr = new char*[vec.size()];
for(size_t i = 0; i < vec.size(); i++){
arr[i] = new char[vec[i].size() + 1];
strcpy(arr[i], vec[i].c_str());
}
BEARBEITEN:
So würden Sie diese Datenstrukturen freigeben, vorausgesetzt, vec hat immer noch die richtige Anzahl von Elementen. Wenn Ihre C-Funktion dieses Array irgendwie ändert, müssen Sie die Größe möglicherweise auf andere Weise ermitteln.
for(size_t i = 0; i < vec.size(); i++){
delete [] arr[i];
}
delete [] arr;
Nochmals BEARBEITEN:
Es ist möglicherweise nicht erforderlich, die Zeichenfolgen zu kopieren, wenn Ihre C-Funktion die Zeichenfolgen nicht ändert. Wenn Sie erläutern können, wie Ihre Benutzeroberfläche aussieht, können wir Ihnen sicher besser helfen.
Sie müssen zeigen, wie man dieses Array löscht, zumal es so kompliziert ist. Verwendung nicht vergessen delete[].
– Nicol Bolas
13. August 2011 um 6:03 Uhr
Dies leckt, wenn die new in dem for wirft. Es wäre viel besser, a zu verwenden std::vector.
– Mankarse
13. August 2011 um 7:21 Uhr
Luca Danton
Eine C++0x-Lösung, bei der Elemente von std::string werden garantiert zusammenhängend gespeichert:
std::vector<std::string> strings = /* from somewhere */;
int nterms = /* from somewhere */;
// using std::transform is a possibility depending on what you want
// to do with the result of the call
std::for_each(strings.begin(), string.end(), [nterms](std::string& s)
{ ModelInitialize(&s[0], nterms); }
Wenn die Funktion null ihr Argument beendet, dann nach dem Aufruf (s.begin(), s.end()) vielleicht nicht aussagekräftig. Sie können dies nachbearbeiten, um das zu beheben:
s = std::string(s.begin(), std::find(s.begin(), s.end(), '\0'));
Eine aufwändigere Version, die jede Zeichenfolge separat in a kopiert char[]:
const char* ist auch dasselbe wie char*, nur unterschiedlich in der const_ness, Ihre Schnittstellenmethode akzeptiert sowohl konstante als auch nicht konstante Zeichenfolgen.
Gibt c_str() kein const char zurück? Wird das ein Problem sein, wenn ich nur ein Zeichen* brauche?
Ja, es gibt eine konstante Zeichenfolge zurück und nein, es sollte kein Problem geben
const char*a="something";
////whatever it is here
const char* retfunc(const char*a)
{
char*temp=a;
//process then return temp
}
Die Rückgabe eines lokalen Objekts wird von vielen Leuten nicht akzeptiert, und dieses kleine Beispiel wird so wie es ist bereitgestellt.
Dieser Code wird nicht kompiliert. Es ist weder legal noch sicher, einen Zeiger auf eine Konstante einem Zeiger auf eine Nicht-Konstante zuzuweisen.
– Mankarse
13. August 2011 um 7:28 Uhr
“Die Rückgabe eines lokalen Objekts wird von vielen Leuten nicht akzeptiert” // Nein, das ist Müll. Rückkehr a Hinweis oder Zeiger zu einem lokalen Objekt wird von der Sprache oder von Compilern nicht akzeptiert. Aber das ist nicht dasselbe.
– Leichtigkeitsrennen im Orbit
13. August 2011 um 15:52 Uhr
Und dieser Code ist nicht nur ungültig, sondern selbst wenn Sie es wären eigentlich warf die weg constness, es wäre eine schrecklich dumme Sache zu tun.
– Leichtigkeitsrennen im Orbit
13. August 2011 um 15:52 Uhr
Danke Tomalak für deine Korrekturen und Kommentare, bitte sei nicht zu hart, es ist eine andere Idee, wie man es sicherer macht, hängt immer noch von der tatsächlichen Codierungserfahrung des OP ab …
– Markus
13. August 2011 um 15:59 Uhr
“const char* ist auch das gleiche wie char*, nur anders in der const_ness”, das ist so hilfreich wie die Aussage, dass “Äpfel das gleiche wie Orangen sind, nur anders”
Dieser Code wird nicht kompiliert. Es ist weder legal noch sicher, einen Zeiger auf eine Konstante einem Zeiger auf eine Nicht-Konstante zuzuweisen.
– Mankarse
13. August 2011 um 7:28 Uhr
“Die Rückgabe eines lokalen Objekts wird von vielen Leuten nicht akzeptiert” // Nein, das ist Müll. Rückkehr a Hinweis oder Zeiger zu einem lokalen Objekt wird von der Sprache oder von Compilern nicht akzeptiert. Aber das ist nicht dasselbe.
– Leichtigkeitsrennen im Orbit
13. August 2011 um 15:52 Uhr
Und dieser Code ist nicht nur ungültig, sondern selbst wenn Sie es wären eigentlich warf die weg constness, es wäre eine schrecklich dumme Sache zu tun.
– Leichtigkeitsrennen im Orbit
13. August 2011 um 15:52 Uhr
Danke Tomalak für deine Korrekturen und Kommentare, bitte sei nicht zu hart, es ist eine andere Idee, wie man es sicherer macht, hängt immer noch von der tatsächlichen Codierungserfahrung des OP ab …
– Markus
13. August 2011 um 15:59 Uhr
“const char* ist auch das gleiche wie char*, nur anders in der const_ness”, das ist so hilfreich wie die Aussage, dass “Äpfel das gleiche wie Orangen sind, nur anders”
– 463035818_ist_keine_Nummer
14. November 2017 um 13:51 Uhr
13870900cookie-checkstd::Vektor zum char*-Arrayyes
Was ist die genaue C-Schnittstelle. Wir können verschiedene Dinge tun, je nachdem, wo sich die const befinden und wie die Funktion den Speicher während der Verwendung behandelt (C-Funktionen können unangenehme Dinge tun, wie z. B. den Aufruf von realloc).
– Martin York
13. August 2011 um 6:03 Uhr
Model* ModelInitialize (char *fnames, int nterms)
– Christopher DuBois
13. August 2011 um 6:14 Uhr
Diese Funktion akzeptiert
char*
nichtchar**
wie in deiner frage. Welches ist es?– Luc Danton
13. August 2011 um 6:39 Uhr
verkohlen*. Sorry für die Verwirrung. Ich habe versehentlich eine Funktion betrachtet, die char** fnames als Argument akzeptiert und später ModelInitialize aufruft.
– Christopher DuBois
13. August 2011 um 6:46 Uhr
Die Funktionssignatur enthält eindeutig nicht genügend Informationen, um die richtige Vorgehensweise zu bestimmen. Ist Eigentum an
fnames
übertragen inModelInitialize
? (wenn ja: wie muss er zugeordnet worden sein?) Ist der aufrufende Code dazu gedachtdelete
,free
oder anderweitig freigebenModel
zurückgekehrt vonModelInitialize
? (wenn ja: wie muss es freigegeben werden?) Mussfnames
ein nullterminierter String sein? Auf welche Weise evtlfnames
modifiziert sein?– Mankarse
13. August 2011 um 7:43 Uhr