Speicherleck bei Neuzuweisung eines Strings?



  • Hi erstmal!
    Lerne gerade C / C++ und hab eine Frage. Wenn ich einen Zeiger auf Char mit einem String initialisiere, und dem Zeiger danach einen neuen String zuweise, entsteht dann ein Speicherleck oder wird der Speicher für den ersten String automatisch wieder freigegeben?

    char *s = "String1";
    s = "String";
    


  • Das ist nicht erlaubt. Undefiniertes Verhalten.



  • nimm C++Strings und keine C-Strings. Dann gibts auch keine Speicherlecks und solchen Mist.



  • drakon schrieb:

    Das ist nicht erlaubt. Undefiniertes Verhalten.

    Was soll daran undefiniert sein, einen Zeiger umzuhängen?

    pumuckl schrieb:

    nimm C++Strings und keine C-Strings. Dann gibts auch keine Speicherlecks und solchen Mist.

    Stringliterale erzeugen keine Speicherlecks, da sie im statischen/globalen Speicher liegen und somit bei Programmende zerstört werden. Und für konstante Stringliterale finde ich std::string ehrlich gesagt arg übertrieben.

    Ist es das fehlende const , das euch stört?



  • drakon schrieb:

    Das ist nicht erlaubt. Undefiniertes Verhalten.

    Quatsch!

    Es entsteht weder ein Speicherleck, noch wird Speicher freigegeben. Alle Stringliterale, die im Programm vorkommen, stehen vom Programmbeginn an irgendwo im Speicher. s zeigt hier auf ein solches Literal. Jetzt biegt man s auf ein anderes Literal um. Das auch schon vorher existiert hat. Das, worauf s zuerst gezeigt hat, ist auch nicht unbedingt verloren. Das hängt vom Code ab:

    int f() {
      char *s = "hallo";
      cout << s;
      s = "blub";
    }
    

    s wird jedesmal wieder mit demselben Literal "hallo" initialisiert, "hallo" wird ausgegeben, dann wird s umgebogen.

    Es wird davon ausgegangen, dass die Stringliterale unveränderlich sind. Sie können z.B. in einem schreibgeschützten Speicherbereich untergebracht werden. Daher ist das Verändern eines Stringliterals undefiniert:

    char *s = "hallo";
    s{0} = 'H'; // PENG!
    

    Man sollte daher Zeiger auf Stringliterale grundsätzlich als const char* deklarieren, damit der Compiler solche Fehler abfängt. Der Typ char* wird dafür überhaupt nur noch wegen der Abwärtskompatibilität unterstützt.



  • Bashar schrieb:

    drakon schrieb:

    Das ist nicht erlaubt. Undefiniertes Verhalten.

    Quatsch!

    Es entsteht weder ein Speicherleck, noch wird Speicher freigegeben. Alle Stringliterale, die im Programm vorkommen, stehen vom Programmbeginn an irgendwo im Speicher. s zeigt hier auf ein solches Literal. Jetzt biegt man s auf ein anderes Literal um.

    Mist, ja. Bin atm ein wenig verpeilt.. 🙄



  • Alles klar, dankeschön!
    Bin im Lehrbuch gerade am Kapitel "Dynamische Speicherverwaltung" und da wurde diese Frage irgendwie nicht so richtig beantwortet.

    Nur nochmal zusammen gefasst. Wenn ich einem String nach der Initialisierung einen neuen "Wert" zuweise kann ich mir free() oder sonstwas sparen und einfach weitermachen ohne mir über mögliche Folgen den Kopf zerbrechen zu müssen.



  • Das gilt nur für Stringliterale, also Zeichenketten, die mit Anführungszeichen im Code stehen:

    const char* Str = "ich bin ein Stringliteral";
    

    Sobald du selbst mit new oder malloc() Speicher anforderst, brauchst du dich wieder um die Freigabe zu kümmern. Aber in diesen Fällen wäre std::string angebrachter.



  • AxXxel001 schrieb:

    Nur nochmal zusammen gefasst. Wenn ich einem String nach der Initialisierung einen neuen "Wert" zuweise kann ich mir free() oder sonstwas sparen und einfach weitermachen ohne mir über mögliche Folgen den Kopf zerbrechen zu müssen.

    Nur wenn du ausschließlich mit Stringliteralen arbeitest. Sobald du per strcpy oder andere Funktionen Strings zur Laufzeit zusammenschnibbelst musst du mit entsprechenden buffern arbeiten und dir auch immer Gedanken machen ob und wie du den Speicher der Buffer wieder freigibst (und bei Zugriffen darauf überlegen ob der buffer noch existiert, d.h. ob der Zugriff gültig ist usw.)

    Solang es sich nur um konstante Stringliterale handelt gebe ich Nexus recht, da reicht ein const char*. (Sind zwar aus historischen Gründen nur char*, aber der const-correctness halber const nehmen). Für alles was darüber hinausgeht std::string.



  • free() kannst du allg vergessen...

    es gibt nur:
    das C++ Pendant heißt delete - und das brauchst du nur, wenn du new eingesetzt hast - zu jedem new gehört ein delete, zu jedem new[] ein delete[].

    char *x = "string";
    ist eigtl falsch, es sollte so lauten:
    const char* x = "string";
    da diese literale direkt im quellcode irgendwo abgelegt werden und du somit nur lese-zugriff hast - deshalb geht das hier auch ins auge:
    `char* x = "string";

    x[0] = 'X';`
    damit so was nicht ausversehen passiert, sollte man const verwenden, wo es nur geht (und sinnvoll ist ^^) - siehe "const correctness".

    was gehen würde, wäre das hier:

    const char* X = "HALLO WELT";
    char *x2 = new char[strlen(X)+1]; //+1 für 0-terminierung
    strcpy(X, x2); //oder so ähnlich - ewig nich mehr damit gearbeitet ^^
    x2[5] = '_';
    //X[5] = '_'; - geht nicht (s.o.)
    std::cout << x2 << std::endl;
    delete[] x2; //da du den speicher mit new[] angefordert hast
    

    bb



  • Okay, alles verstanden.

    Danke!


Anmelden zum Antworten