string nach c array



  • 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_str

    314159265358979 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.


  • Mod

    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, if pos == size() , the const version returns charT() . 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.


  • Mod

    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()


Anmelden zum Antworten