string nach c array
-
Mahlzeit,
klappt dieser Code hier immer?
char str[64]; std::string otherStr = ... strncpy(str, otherStr.c_str(), 63);Oder koennte das mal schief gehen?
-
eigentlich sollte nichts passieren, also nicht böses.
du überschreitest die arraygrenzen nicht und du hast speicher angefordert...
-
Ich frage vor allem, weil ich nicht weiss ob std::string den C String immer mit einer 0 terminiert. Wenn das nicht der Fall waere, waere str ja auch nicht 0 terminiert und wurde dann spaeter bei Benutzung von string funktionen wie strcmp() explodieren.
-
Natürlich ist der 0-terminiert, ergäbe anders keinen Sinn.
-
Die Rückgabe von c_str() ist immer nullterminiert. Allerdings ist Dein Zielstring nicht nullterminiert, wenn otherStr länger als 63 Zeichen ist.
-
314159265358979 schrieb:
Natürlich ist der 0-terminiert, ergäbe anders keinen Sinn.
Wieso sollte das keinen Sinn ergeben? Man koennte std::string absolut ohne 0 Terminierer implementieren.
-
LordJaxom schrieb:
Die Rückgabe von c_str() ist immer nullterminiert. Allerdings ist Dein Zielstring nicht nullterminiert, wenn otherStr länger als 63 Zeichen ist.
Also am besten so machen, um 100%ig sicher zu gehen?
strncpy(str, otherStr.c_str(), 63); str[63] = 0;?
-
konvertierer() schrieb:
314159265358979 schrieb:
Natürlich ist der 0-terminiert, ergäbe anders keinen Sinn.
Wieso sollte das keinen Sinn ergeben? Man koennte std::string absolut ohne 0 Terminierer implementieren.
Ist richtig, aber das Ergebnis von c_str ist wie gesagt garantiert terminiert. Um dein Vorhaben sicherer zu machen, würde ich einen vector benutzen. Oder du musst bei deiner Lösung halt immer das letzte Zeichen mit 0 überschreiben.
void C(char* str) { str[0] = 'x'; } int main() { std::string s = "hallo"; std::vector<char> cstr(s.begin(), s.end()); cstr.push_back('\0'); C(&cstr[0]); s.assign(cstr.begin(), cstr.end()); std::cout << s; return 0; }
-
brotbernd schrieb:
Um dein Vorhaben sicherer zu machen, würde ich einen vector benutzen.
Warum so kompliziert und nicht einfach str.substr(0, 63).c_str() ?
-
konvertierer() schrieb:
Ich frage vor allem, weil ich nicht weiss ob std::string den C String immer mit einer 0 terminiert.
Dann schaut man am besten mal nach
string::c_str314159265358979 schrieb:
Natürlich ist der 0-terminiert, ergäbe anders keinen Sinn.
Dass es garantiert ist, dass er 0-terminiert ist haben wir nun festgestellt. Was das allerdings mit Sinn zu tun hat ist mir schleierhaft. Gibt schliesslich auch data() (nicht 0-terminiert).
-
Es macht Sinn, sich an C-Konventionen zu halten. Mein Gott, ist das so schwer?
.data() gibt ja auch keinen String zurück. <.<
-
314159265358979 schrieb:
Es macht Sinn, sich an C-Konventionen zu halten. Mein Gott, ist das so schwer?
.data() gibt ja auch keinen String zurück. <.<Wieso sollte sich eine C++ Klasse zwingend an C Konventionen halten?
-
314159265358979 schrieb:
Es macht Sinn, sich an C-Konventionen zu halten. Mein Gott, ist das so schwer?
.data() gibt ja auch keinen String zurück. <.<Der Rückgabewert von data() und c_str() ist absolut identisch, nämlich: const char *
-
Weil es dumm wäre, eine Inkompatibilität mit C-Funktionen künstlich herzustellen.
Falsch, sie haben den selben Rückgabetyp, aber .data() liefert einen Zeiger auf Daten, .c_str() einen String.
-
notLoggedIn schrieb:
Der Rückgabewert von data() und c_str() ist absolut identisch, nämlich: const char *
const char* ist der Typ, nicht der Wert. Der Wert kann durchaus unterschiedlich sein. data() muss nämlich nicht nullterminiert sein.
konvertierer() schrieb:
Wieso sollte das keinen Sinn ergeben? Man koennte std::string absolut ohne 0 Terminierer implementieren.
Kann man, tut man vermutlich auch

314159265358979 schrieb:
Natürlich ist der 0-terminiert, ergäbe anders keinen Sinn.
So ohne Begründung ist das garnicht so "natürlich". Das ist es erst, wenn man dazu sagt, dass c_str() eben genau zu dem Zweck existiert, um die Umwandlung in C-Strings zu ermöglichen - was ohne den Nullterminierer tatsächlich sinnfrei wäre.
-
nenene-- schrieb:
Wieso sollte sich eine C++ Klasse zwingend an C Konventionen halten?
Weil die Funktion
c_str(C-String) heißt und hier explizit bereits im Namen gesagt wird, dass es ein C-Style String ist, eine Funktion, die extra dafür eingebaut wurde, um C-kompatibel zu sein.
-
pumuckl schrieb:
konvertierer() schrieb:
Wieso sollte das keinen Sinn ergeben? Man koennte std::string absolut ohne 0 Terminierer implementieren.
Kann man, tut man vermutlich auch

Allgemeine, ungewertete Info: Die String-Implementierung beim g++ ist immer nullterminiert. Ein Kommentar im Code sagt, dass der C++-Standard 21.3.4 dies erzwingt. Ich kann mich dem zwar nicht ganz anschließen, aber ich stimme zu, dass ein Programmierer wirklich absichtlich böse sein müsste, um dies anders zu implementieren. Es wäre nämlich nötig bei jedem Elementzugriff, eine Fallunterscheidung zu machen, die man sich ansonsten spart. (Falls man ohnehin einen Zugriff mit Test auf Überschreitung der Grenzen hat ist das hingegen geschenkt).
P.S.: 21.3.4 sagt
21.3.4: basic_string element access
`const_reference operator []( size_type pos ) const ;
reference operator []( size_type pos );`
Returns: If
pos < size(), returns *(begin() + pos ). Otherwise, ifpos == size(), the const version returnscharT(). Otherwise, the behavior is undefined.
-
Interessant.
Zitat aus "Effective STL" von Scott Meyers:
...The approach to getting a pointer to container data that works for vectors isn't reliable for strings, because (1) the data for strings are not guaranteed to be stored in contiguous memory, and (2) the internal representation of a string is not guaranteed to end with a null character. This explains the existence of the string member function c_str, which returns a pointer to the value of the string in a form designed for C. We can thus pass a string s to this function....
Was ja im Widerspruch zum Kommentar mit Bezug auf 21.3.4 steht.
21.4.1.5 in N3242 sagt zwar, dass ein zusammenhängender Speicherbereich genutzt werden sollte, aber bezüglich der 0-terminierung habe ich nichts gefunden.
-
Ich seh da gar keinen Widerspruch.
returns *(begin() + pos )
Also Iterator auf den Anfang um pos erhöht und dereferenziert. Wie das implementiert steht da ja nicht.
-
brotbernd schrieb:
Ich seh da gar keinen Widerspruch.
returns *(begin() + pos )
Also Iterator auf den Anfang um pos erhöht und dereferenziert. Wie das implementiert steht da ja nicht.
Es geht glaube ich eher um die Klausel, dass bei pos == size() der Wert charT() zurückgegeben wird. Wenn du nicht bei jedem Zugriff da drauf prüfen willst, dann sollte da besser gleich der passende Wert stehen.
-
SeppJ schrieb:
Es geht glaube ich eher um die Klausel, dass bei pos == size() der Wert charT() zurückgegeben wird. Wenn du nicht bei jedem Zugriff da drauf prüfen willst, dann sollte da besser gleich der passende Wert stehen.
Dabei stellt sich dann natürlich die Frage, wo "da" dann ist. Wenn man den Speicher im vector-style am Stück irgendwo liegen hat ist das klar, aber wenns eben nicht am Stück ist heißt der Satz nicht mehr als "Dereferenzierung des end()-Iterators liefert CharT()", da begin()+size() == end()