malloc oder new



  • @_ro_ro sagte in malloc oder new:

    Einfach einen std::vector<char> nehmen und auf die

    Dafür ist mein Compiler zu alt.

    hä? was für einen compiler hast du den genau? denn std::vector existiert schon sehr lange.

    buffer[contentlength] = 0

    Dein buffer ist nur contentlength chars lang, also hat er indizes von 0 bis contentlength-1, insbesondere ist contentlength also nicht mehr im Speicherbereich.

    Doch doch, die Terminierung passt schon. Wenn ich nicht terminiere kriege ich im Browser ein Speicherabbild bis zun nächsten zufälligen Nullbyte 😉

    It aber immer noch falsch. Denn ein char[<size>] array hat indices von 0 bis <size>-1.
    Daher ist ein array[<size>] zugriff auserhalb der array grenzen!

    Da contentlength die gestamlänge des "content" darstellt, aber AFAIK ohne ein nullterminator, musst du bei der größe des Buffers eins dazu zählen.
    Auf mein Beispiel bezogen sieht die Anpassung wie folgt aus:

    // das +1 damit platz für den c-string nullterminator vorhanden ist
    std::vector<char> buffer(contentlength+1, 0);
    // Hier contentlength statt buffer.size() damit nicht versucht wird ein byte zu viel zu lesen.
    cin.read(buffer.data(),contentlength);
    rawdata = buffer.data();
    


  • @_ro_ro sagte in malloc oder new:

    @firefly u.a.

    danke!!! Also ich habe 199711 ist das C++11?

    Das ist die allererste ISO Norm sprich C++98. Auch da existierte bereits std::vector. Allerdings ist das extrem alt.


  • Gesperrt

    Ich werfe mal std::string in den Raum... es sei denn, es soll gar nicht versucht werden, diesen nachzubauen.



  • @_ro_ro sagte in malloc oder new:

    Dafür ist mein Compiler zu alt.

    Du mußt noch den passenden Header <vector> einbinden.



  • @_ro_ro sagte in malloc oder new:

    Moin 😉

    Anfängerfrage: Was ist besser? Code untenstehend, maskiert ist der Code im C-Style.

    Danke im Vorab!!!

                char * buffer = new char(contentlength);
                cin.read(buffer, contentlength);
                buffer[contentlength] = 0; // Terminieren!!!
                rawdata = buffer;
                delete []buffer;
    

    new char(contentlength) fordert Speicher für einen char an und initialisiert diesen char dann mit dem Wert contentlength.
    Um ein char Array anzufordern musst du new char[length] schreiben.

    Dann ist noch contentlength als Länge falsch. Du musst genau so wie in C contentlength + 1 nehmen, da du ja auch contentlength + 1 Elemente verwendest.

    Und weiters macht folgendes keinen Sinn:

                 rawdata = buffer;
                 delete []buffer;
    

    Streng genommen ist das zwar bis dahin noch kein Fehler. Nur macht es eben keinen Sinn. Du darfst das auf was rawdata Zeigt danach nicht mehr verwenden, weil es bereits freigegeben wurde. D.h. die Zuweisung rawdata = buffer; macht keinen Sinn. Dabei wird ja nur die Adresse des Arrays von buffer nach rawdata kopiert - nicht das Array selbst. Und das Array selbst gibst du mit delete []buffer; frei.

    EDIT: OK, habe übersehen dass rawdata ist ein string ist. Dann ist es OK.



  • @firefly sagte in malloc oder new:

    Daher ist ein array[<size>] zugriff auserhalb der array grenzen!

    Das ganze läuft unter URL http://rolfrost.de/foo.chtml

    und da wird bei jedem Request eine 1.5 MB große Binärdatei auf eine assoziative Datenstruktur gelesen. Wenn mein Serializer nicht bytegenau arbeiten würde oder die Terminierung nicht bytegenau sitzen würde stünde da Datenmüll im Browser.

    Viele Grüße 😉



  • @_ro_ro sagte in malloc oder new:

    Doch doch, die Terminierung passt schon. Wenn ich nicht terminiere kriege ich im Browser ein Speicherabbild bis zun nächsten zufälligen Nullbyte

    Die Zeile buffer[contentlength] = 0; macht schon Sinn. Nur wie du den Speicher anforderst ist falsch, siehe oben.

    Dafür ist mein Compiler zu alt.

    Glaub ich nicht. Welchen Compiler verwendest du denn?

    Davon abgesehen kannst du es auch einfach so machen:

                rawdata.resize(contentlength);
                cin.read(&rawdata[0], contentlength);
    

  • Gesperrt

    Ich bewundere hustbear für seine Geduld, auch auf den 100. Fragesteller, der selber keinerlei Eigeninitiative zeigt, in angemessener Art und Weise zu antworten. 🙂

    Oder anders: Ihr werdet möglicherweise getrollt gerade...



  • @Th69 sagte in malloc oder new:

    @_ro_ro sagte in malloc oder new:

    Dafür ist mein Compiler zu alt.

    Du mußt noch den passenden Header <vector> einbinden.

    Ahhhh 😉

    Hatte ich nicht, Danke!!!

    MFG



  • @_ro_ro:
    Die Nullterminierung macht bei Binärdaten überhaupt keinen Sinn (da das '\0'-Zeichen in den Daten selbst vorkommen kann)!
    Und somit auch die Zuweisung

    rawdata = buffer;
    

    nicht, da nachher im String rawdata nur die Zeichen bis zum ersten Nullzeichen drinstehen...
    Du solltest daher bei Binärdaten, wie schon geschrieben, std::vector<char> verwenden.



  • @firefly sagte in malloc oder new:

    cin.read(buffer.data(),contentlength);
    rawdata = buffer.data();

    Danke Glühwürmchen ,

    dieser Dreizeiler gefällt mir, hochgeladen, kompiliert und geht 😉

    Schönes Wochenende!!!!



  • @Th69

    ich habe ja auch nicht geschrieben daß ich binärdaten terminiere. Mein Serializer sieht so aus:

    // Eigener Namespace für dies und das
    namespace my{
        // BigEndian to Little Endian
        // Und umgekehrt
        uint32_t endian( uint32_t be){
            uint8_t a = be >> 24;
            uint8_t b = be >> 16 & 0xFF;
            uint8_t c = be >> 8 & 0xFF;
            uint8_t d = be & 0xFF;
            return (d << 24) + (c << 16) + (b << 8) + a;
        };
        // Routingtable Binary einlesen
        int read_eav_file( map< string, map<string, string> > &eav ){
            // mode "rb": lesen in binary mode
            FILE *fp = fopen(BINPATH, "rb");
            if(fp == NULL){
                throw string("Error open File dbf.bin");
            }
    
            //´Puffer für die Längenangaben
            uint32_t lens[3];
    
            // Algorithmus: Lese 3 mal jeweils 4 Bytes
            while( fread(lens,4,3,fp) ){
                int elen = endian(lens[0]);
                int alen = endian(lens[1]);
                int vlen = endian(lens[2]);
    
                char *ent;
                ent = (char*)malloc( elen + 1 );
                fread(ent, elen, 1, fp);
                ent[elen] = 0;
                char *att;
                att = (char*)malloc(alen + 1);
                fread(att, alen, 1, fp);
                att[alen] = 0;
                char *val;
                val = (char*)malloc(vlen + 1);
                fread(val, vlen, 1, fp);
                val[vlen] = 0;
    
                eav[ent][att] = val;
                free(ent);
                free(att);
                free(val);
            }
            fclose(fp);
            return 0;
        }
    
    };
    
    

    Und dieser von mir ausgeheckte Algorithmus bewährt sich seit 20 Jahren 😉

    Kompatibel zu PHP, Perl und JavaScipt.

    MFG


  • Gesperrt

    @_ro_ro
    Du mischt da C mit C++, das sollte man nicht tun.

    Und https://de.wikipedia.org/wiki/Loop_unrolling#Teilweises_Entrollen ist eigentlich auch nicht "neu"... oder hast du das als Erster erfunden?



  • @nameName sagte in malloc oder new:

    @_ro_ro
    Du mischt da C mit C++, das sollte man nicht tun.

    Und https://de.wikipedia.org/wiki/Loop_unrolling#Teilweises_Entrollen ist eigentlich auch nicht "neu"... oder hast du das als Erster erfunden?

    Mein Serializer entrollt gar nichts.

    MFG



  • @_ro_ro sagte in malloc oder new:

    Und dieser von mir ausgeheckte Algorithmus bewährt sich seit 20 Jahren

    Um mal auf deine Frage malloc oder new? zurückzukommen.

    In halbwegs moderneren C++ nutzt man new nur noch sehr sehr selten und dann nur in gut begründeten Ausnahmefällen. Das Schlüsselwort malloc gar nicht mehr.

    Manuelle Speicherverwaltung mittels new oder malloc,... ist nämlich sehr fehleranfällig. Einmal ein delete oder free vergessen und schon existiert Speicher, welcher nicht freigegeben und nicht zugreifbar ist. Passiert dies periodisch, wird dein Programm oder System abstürzen. Stell dir z.B. vor deine Funktion read_eav_file würde 20 return Anweisungen enhalten. Wie sähe dann korrekter Code aus?

    Oder man ruft deleteanstatt delete[] auf. Oder man ruft malloc für Klassen auf. Alles vermeidbare Fehler.

    Deswegen existieren in C++ Klassen wie std::vector, std::string, std::unique_ptr, std::shard_ptr welche nur die Aufgabe der Ressourcenverwaltung haben (siehe auch RAII). Damit werden Ressourcen automatisch verwaltet und freigeben. Speicherlöcher passieren damit gar nicht mehr.

    Die Frage malloc oder new? beantwortet sich also folgendermaßen: Nutze weder das eine noch das andere, sondern nutze die Containers library oder Memory management library von C++.

    Siehe auch:
    https://en.cppreference.com/w/



  • @Quiche-Lorraine

    danke Quiche Lorraine für Ihre ausführliche und verständliche Antwort. Vector-Objekte sind eine feine Sache, wieder was dazugelernt (und auch schon nachgelesen). In Fakt habe ich noch einige Zeilen ANSI-C in meinem Code zu überarbeiten. C++ ist mächtig gewaltig, da fange ich gerade erst an 😉

    Viele Grüße, schönen Sonntag und kommen Sie gut ins Neue Jahr!


  • Gesperrt

    @_ro_ro sagte in malloc oder new:

    Mein Serializer entrollt gar nichts.

    Ok, wenn du das selber nicht erkennst, dann will ich nix gesagt haben... Schönen Abend noch.



  • @nameName

    Mein Algorithmus beherzigt das was Niklaus Wirth mal schrieb, nämlich daß Dateien Sequenzen sind und von daher sequentiell gelesen und geschrieben werden. Wenn Sie sich dagegen die Exif-Spezifikation anschauen, da sind die Exif-Daten in der ganzen Bilddatei verstreut. Und das ist äußerst ineffizient, denn anstatt die Daten sequentiell nacheinander einzulesen, muß der Dateizeiger irrsinnig hin und her bewegt werden.

    Genau das sollte ein Deserialize-Algorithmus ganz sicher nicht tun. Und jetzt sind Sie mal so gut und schauen sie sich meinen Algorithmus noch einmal richtig an. Der macht genau das und rennt straight forward durch die Datei ohne sich nur einmal umzudrehen.

    MFG

            // Algorithmus: Lese 3 mal jeweils 4 Bytes
            while( fread(lens,4,3,fp) ){
                int elen = endian( lens[0] );
                int alen = endian( lens[1] );
                int vlen = endian( lens[2] );
    
                vector <char> ent( 1 + elen );
                vector <char> att( 1 + alen );
                vector <char> val( 1 + vlen );
                fread(ent.data(), elen, 1, fp);
                fread(att.data(), alen, 1, fp);
                fread(val.data(), vlen, 1, fp);
                ent[elen] = 0;
                att[alen] = 0;
                val[vlen] = 0;
                string entity = ent.data();
                string attribute = att.data();
                string value = val.data();
                eav[entity][attribute] = value;
            }
    
    

  • Gesperrt

    @_ro_ro sagte in malloc oder new:

    muß der Dateizeiger irrsinnig hin und her bewegt werden.

    Für heutige SSDs ist es wahrscheinlich nicht wichtig, ob einmal viele Daten sequenziell gelesen werden oder zwei unzusammenhängende, kleinere Datenblöcke gelesen werden.

    Und ja, die innere Schleife wurde entrollt, und das ist ja nichts schlechtes.



  • @nameName sagte in malloc oder new:

    @_ro_ro sagte in malloc oder new:

    muß der Dateizeiger irrsinnig hin und her bewegt werden.

    Für heutige SSDs ist es wahrscheinlich nicht wichtig, ob einmal viele Daten sequenziell gelesen werden oder zwei unzusammenhängende, kleinere Datenblöcke gelesen werden.

    Das mag sein. Es ist jedoch unsinnig, Random Access auf Byte-Ebene abzubilden, genau darauf läuft es ja hinaus bei Exif. Und das ist Schrott.

    Und ja, die innere Schleife wurde entrollt, und das ist ja nichts schlechtes.

    Wo bitte sehen Sie denn in meinem DeSerialize-Algorithmus eine innere Schleife!?

    MFG


Anmelden zum Antworten