Problem mit malloc und new



  • Serious_Bob schrieb:

    Ich bringe mir zur Zeit C++ bei

    Schön. Was verwendest Du denn als Lehrmaterial?

    Serious_Bob schrieb:

    Wieso? Ich versuche das schon seit Tagen zu verstehen und verzweifle so langsam dran.

    Du hast vergessen, Platz für einen Nullterminator zu machen und diesen mitzukopieren.

    Darüber hinaus hast Du noch die Dreierregel verletzt. Das wird Dir als nächstes zum Verhängnis.

    Sonst hast Du noch ein paar überflüssßge void s im Quellcode, die man heutzutage nicht mehr schreibt. Außerdem frage ich mich, warum Du eine Windows-spezifische main-Funktion verwendest. Das ist doch gar nicht nötig.

    kk



  • Zuerstmal danke für die schnellen antworten 🙂

    u dran denken, daß die Standard-Ausgabe für char* ausgibt bis zum Nullterminator. Du brauchst eine eigene Ausgabe.
    Auch der Debugger gibt bis zur '\0' am Ende aus oder wenigstens recht weit. Laß Dich von ihm nicht verhohnepiepeln.

    Das war schon alles, ich wusste nicht, dass der Debugger so weit ließt, ich hänge also einfach noch eine '\0' hinten dran, jetzt zeigt der Debugger auch das richtige an. Danke dir!

    Schreibe doch die Funktion strlen(..) selbst, das hilft ev. für's Verständnis.

    Hab ich auch noch vor 🙂

    ps: Dein Buch schätze ein auf ein relativ gutes der mittleren 90-er Jahre. Vielleicht tust Du Dir einen gefallen, etwas aktuelles zu holen.

    Buch? 😃 Ne ich hab Kenntnisse in Java, C#, ABAP, PHP. Für C++ wollt ich mir nicht auch noch ein Buch kaufen 😉 Das einzige Problem ist, dass C++ halt sehr Prozessor nah ist und ich da erstmal durchsteigen muss.

    arüber hinaus hast Du noch die Dreierregel verletzt. Das wird Dir als nächstes zum Verhängnis.
    Sonst hast Du noch ein paar überflüssßge voids im Quellcode, die man heutzutage nicht mehr schreibt. Außerdem frage ich mich, warum Du eine Windows-spezifische main-Funktion verwendest. Das ist doch gar nicht nötig.

    Die Klasse ist noch lange nicht fertig, aber danke für den Tipp!
    Das void im Destruktor ist auch nicht beabsichtigt gewesen, das ist noch vom Erstellen der Klasse übrig. Die Windows-spezifische main-Funktion wird später mal wichtig werden für mich.

    Danke nochmal für alle Antworten.

    Gruß



  • Das einzige Problem ist, dass C++ halt sehr Prozessor nah ist und ich da erstmal durchsteigen muss.

    Ist doch kein Problem. Ausserdem kann man mit C++ auch highlevel programmieren.



  • krümelkacker schrieb:

    Du hast vergessen, Platz für einen Nullterminator zu machen und diesen mitzukopieren.

    Der BOString hat eine Längenangabe und braucht keinen Nullterminator.



  • Buch macht kluch. Einfach mal "Effektiv C++ programmieren" durchlesen. Nur so zur Sicherheit, daß Du nicht gegen die Sprache programmierst.



  • Serious_Bob schrieb:

    Das war schon alles, ich wusste nicht, dass der Debugger so weit ließt, ich hänge also einfach noch eine '\0' hinten dran, jetzt zeigt der Debugger auch das richtige an. Danke dir!

    Und das möchtest du jedes Mal machen? Verwende lieber das hier:

    //Ein zusätzliches Zeichen für '\0':
    this->len=strlen(str);
    this->str=new char[this->len+sizeof(char)];
    
    //Ist doch so viel lesbarer und einfacher, oder?
    for(unsigned int i=0;str[i];i++)
        this->str[i]=str[i];
    this->str[this->len]=0;
    

    Serious_Bob schrieb:

    Das einzige Problem ist, dass C++ halt sehr Prozessor nah ist und ich da erstmal durchsteigen muss.

    Assembler ist sehr nahe am Prozessor, C++ ist nur maschinennah. Durch die hohe Abstraktion ist man in C++ in der Lage, Low-Level-Befehle mit einfachen Funktionen aufzurufen, die zudem plattformunabhängig sein können.

    Serious_Bob schrieb:

    Die Klasse ist noch lange nicht fertig, aber danke für den Tipp!
    Das void im Destruktor ist auch nicht beabsichtigt gewesen, das ist noch vom Erstellen der Klasse übrig. Die Windows-spezifische main-Funktion wird später mal wichtig werden für mich.

    Eine Klasse ist eine Klasse, kein Programm. Und selbst, wenn der gesamte Quellcode in einer Klasse steckt, wird sie doch nicht zum Programm. Kapselung heißt das Zauberwort, und wenn ein Befehl in deiner Klasse Auswirkungen auf das Programm an sich (und nicht nur auf die Instanz) hat, solltest du das Design noch einmal überdenken - später kannst du dann mit deiner geschlossenen Klasse programmieren, ohne darüber nachdenken zu müssen, wie du was implementiert hast.



  • Der aus dem Westen ... schrieb:

    Und das möchtest du jedes Mal machen? Verwende lieber das hier:

    //Ein zusätzliches Zeichen für '\0':
    this->len=strlen(str);
    this->str=new char[this->len+sizeof(char)];
    
    //Ist doch so viel lesbarer und einfacher, oder?
    for(unsigned int i=0;str[i];i++)
        this->str[i]=str[i];
    this->str[this->len]=0;
    

    Ihgittigitt.
    Nö, nicht so nachmachen.



  • Verklärst du mir auch, warum, wieso und weshalb? 🤡 Nun gut, es mögen Leerzeichen fehlen, aber jeder hat nun mal seinen Stil ...



  • Der aus dem Westen ... schrieb:

    //Ein zusätzliches Zeichen für '\0':
    this->len=strlen(str);
    this->str=new char[this->len+sizeof(char)];
    
    //Ist doch so viel lesbarer und einfacher, oder?
    for(unsigned int i=0;str[i];i++)
        this->str[i]=str[i];
    this->str[this->len]=0;
    

    Was daran lesbarer sein soll...?!
    sizeof(char) ist immer 1.

    BOBString::BOBString(const char *str) {
        // FIXME: str auf NULL überprüfen, sonst kracht es.
        this->str = new char[this->len = std::stlren(str) + 1];
        std::strcpy(this->str, str);
    }
    


  • sizeof char == 1 schrieb:

    Was daran lesbarer sein soll...?!

    Für mich ist es nun mal lesbarer, find' dich damit ab. Jedes mal, wenn jemand

    int * Pointer = new int [10];
    

    schreibt, möchte ich gleichzeitig heulen und den Programmierer strangulieren.

    BOBString::BOBString(const char *str) {
        // FIXME: str auf NULL überprüfen, sonst kracht es.
        this->str = new char[this->len = std::stlren(str) + 1];
        std::strcpy(this->str, str);
    }
    

    Das einzige, was mir (schon vorher, und zwar Sekunden vor deinem Post) aufgefallen ist, ist dass ich wohl malloc und new ein bisschen durcheinandergebracht habe (sizeof, was habe ich mir dabei gedacht ... :().

    Zeiger auf NULL prüfen ist nicht nötig, bei new wird einfach eine std::bad_alloc -Exception geworfen. Mann, das habe ich mal voll ausgenutzt ... im catch -Block ein goto auf hinter try , und ich hatte blitzschnell 2 Gigabyte reservierten Speicher ... 😃



  • Und selbst, wenn sizeof(char)!=1 wäre, dann wäre

    str=new char[this->len+sizeof(char)];
    

    erst recht töricht, weil in [] die Anzahl steht und nicht die Größe in Bytes.

    Aber mir scheint, Du wolltest damit rohen Speicher besorgen.
    Das macht man wiederum mit

    str=::operator new(len+1);
    

    Und wenn man schon strlen benutzt, darf's auch ein bißchen memcpy sein.

    Lesbarer fände ich die Schleife mit str[i]!='\0'.

    Die Schleife ist seltsam. Sie soll auf jeden Fall mindestens einen char kopieren? Der FI/AE würde das eine fußgesteuerte Schleife nennen. K&R würden while(*dst++=*src++); schreiben. Irgendwie weigert sie sich, hübsch zu werden.



  • Wieso wird denn hier ständig this verwendet, wo es nicht nötig ist? Es bläht den Code unnötig auf, und das empfinde ich persönlich als schlecht lesbar.



  • Der aus dem Westen ... schrieb:

    Jedes mal, wenn jemand

    int * Pointer = new int [10];
    

    schreibt, möchte ich gleichzeitig heulen und den Programmierer strangulieren.

    Geht mir ähnlich. Aber waagerecht noch nicht so schlimm.
    Es gibt Leute, die machen es senkrecht!

    this->len=strlen(str);
    
    this->str=new char[this->len+sizeof(char)];
    
    //Ist doch so viel lesbarer und einfacher, oder?
    for(unsigned int i=0;str[i];i++)
        this->str[i]=str[i];
    
    this->str[this->len]=0;
    


  • Serious_Bob schrieb:

    Buch? 😃 Ne ich hab Kenntnisse in Java, C#, ABAP, PHP.
    Für C++ wollt ich mir nicht auch noch ein Buch kaufen 😉

    Ich sehe da keinen Zusammenhang. C++ ist eine völlig andere Sprache. Du tust so, als ob C++ nur ein Dialekt von anderen Dir bekannten Sprachen sei. Da irrst Du Dich aber gewaltig. Du kannst Dir mit einem guten C++ Buch viel Ärger und Zeit sparen. Zeit ist Geld. Glaub's mir, die Investition lohnt sich.

    Kompakte Grundausbilding:
    - Accelerated C++ (Andrew Koenig & Barbara E. Moo)
    - Effective C++ (Scott Meyers)

    Serious_Bob schrieb:

    Das einzige Problem ist, dass C++ halt sehr Prozessor nah ist und ich da erstmal durchsteigen muss.

    In C++ kannst Du Dir die Füße abschießen, ja. Umso wichtiger sind gute Bücher, die Dir die Konzepte der Sprache und bewährte Vorgehensweisen näher bringen.



  • volkard schrieb:

    Aber mir scheint, Du wolltest damit rohen Speicher besorgen.

    Ja, ich habe bereits gesagt, dass ich da Unsinn geschrieben habe. Ich gebe es zu.

    volkard schrieb:

    Und wenn man schon strlen benutzt, darf's auch ein bißchen memcpy sein.

    Hätte ich auch gleich tun können, dafür war ich aber schlichtweg zu faul.

    volkard schrieb:

    Die Schleife ist seltsam. Sie soll auf jeden Fall mindestens einen char kopieren? Der FI/AE würde das eine fußgesteuerte Schleife nennen. K&R würden while(*dst++=*src++); schreiben. Irgendwie weigert sie sich, hübsch zu werden.

    str[i] bedeutet, dass überprüft wird, ob in dem jeweiligen Element ein Nullterminierungszeichen steht. Wenn ja, wird die Schleife abgebrochen, und deshalb wird bei einem leeren String auch nur die 0 eingefügt. Die Anführungszeichen und den Schrägstrich spare ich mir, weil '\0' soweit ich weiß äquivalent zu 0 ist. Insofern würde ich (ohne weitere Kenntnisse darüber, wie hinterher der Maschinencode aussieht) sagen, dass die Schleife ihren Zweck sehr performant erfüllt, oder?

    @_matze: Ein Parameter von ihm heißt 'str', genauso wie ein Element. Ich hätte es auch rausnehmen können (und glaub' mir, ich war kurz davor), aber dann hat mich wieder die Faulheit übermannt.

    volkard schrieb:

    Geht mir ähnlich. Aber waagerecht noch nicht so schlimm.
    Es gibt Leute, die machen es senkrecht!

    Hat auch was von psychischer Folter, zumindest, wenn man Zwangsneurotiker ist.



  • Der aus dem Westen ... schrieb:

    @_matze: Ein Parameter von ihm heißt 'str', genauso wie ein Element. Ich hätte es auch rausnehmen können (und glaub' mir, ich war kurz davor), aber dann hat mich wieder die Faulheit übermannt.

    Das ist mir schon aufgefallen. Ich habe aber nach den Stellen gefragt, an denen this unnötigerweise verwendet wird. Und wenn man konsistent bleiben will, ist es wohl ratsamer, Member oder Parameter umzubenennen, anstatt an ausnahmslos jeder Stelle "this->" zu notieren. Das ist dann letzten Endes auch weniger Arbeit, also der Faulheit zuträglich. 😉



  • Der aus dem Westen ... schrieb:

    str[i] bedeutet, dass überprüft wird, ob in dem jeweiligen Element ein Nullterminierungszeichen steht. Wenn ja, wird die Schleife abgebrochen, und deshalb wird bei einem leeren String auch nur die 0 eingefügt. Die Anführungszeichen und den Schrägstrich spare ich mir, weil '\0' soweit ich weiß äquivalent zu 0 ist. Insofern würde ich (ohne weitere Kenntnisse darüber, wie hinterher der Maschinencode aussieht) sagen, dass die Schleife ihren Zweck sehr performant erfüllt, oder?

    Nicht performanter also mit dem Vergleich gegen den Nullterminator.
    Du läufst, solange str[i] wahr ist.
    Ich laufe, solange str[i] nicht der Nullterminator ist.



  • volkard schrieb:

    Nicht performanter also mit dem Vergleich gegen den Nullterminator.
    Du läufst, solange str[i] wahr ist.
    Ich laufe, solange str[i] nicht der Nullterminator ist.

    Und sofern mich meine kümmerlichen C/C++-Kenntnisse nicht trügen, ist wahr == (!Nullterminator) , oder? Der Nullterminator enthält ja den Wert 0, und der ist negativ, während jedes andere Zeichen positiv ist (zumindest, sofern mich mein Wissen um ASCII, den verschiedenen Codepages und den Unicode-Formaten nicht auf das Glatteis führen). Daher verstehe ich nicht ganz, was du mir sagen willst ...



  • Der aus dem Westen ... schrieb:

    volkard schrieb:

    Nicht performanter also mit dem Vergleich gegen den Nullterminator.
    Du läufst, solange str[i] wahr ist.
    Ich laufe, solange str[i] nicht der Nullterminator ist.

    Und sofern mich meine kümmerlichen C/C++-Kenntnisse nicht trügen, ist wahr == (!Nullterminator) , oder? Der Nullterminator enthält ja den Wert 0, und der ist negativ, während jedes andere Zeichen positiv ist (zumindest, sofern mich mein Wissen um ASCII, den verschiedenen Codepages und den Unicode-Formaten nicht auf das Glatteis führen). Daher verstehe ich nicht ganz, was du mir sagen willst ...

    Ich finde, daß meine Schreibweise eher Klartext ist, während Deine ein kleines Rätsel beinhaltet. Rätsel im Code sind böse meist. Es geht nicht darum, zu zeigen, daß man so vertraut mit C++ ist, daß man sowas normalerweise recht flüssig hinschreiben kann (das können wir alle). Es geht darum, daß man den Code auch noch stockbesoffen recht flüssig lesen kann.



  • Was mich immer noch wundert ist, dass es auf 3 Seiten keiner geschafft hat, die Initialisierungsliste ins Spiel zu bringen?

    class BOBString 
        { 
        public: 
            BOBString(const char *str); 
            ~BOBString(void); 
    
        private: 
            int len; // die Reihenfolge hab ich umgedreht,
            char *str; // sonst serviert einem der Compiler eine Warnung
        };
    
    BOBString::BOBString(const char* str) : len(std::strlen(str)), str(new char[len + 1])
    {
      // String kopieren
      // ...
    }
    

    Wo ich mir jetzt nicht sicher bin, ob strlen() für Null-Zeiger so funktioniert, dass 0 zurückgegeben wird, aber da kann man ja schnell mit ?: Abhilfe schaffen. 🤡


Anmelden zum Antworten