Struct mit AnsiString speichern



  • Mathiable schrieb:

    Kannst du mir mal sagen was daran so altmodisch ist?

    Wie schon oben gesagt wurde sind Funktionen mit implizitem Rückgabetyp int nicht mehr erlaubt, IIRC seit dem C99-Standard. Im C++-Standard von 1998 ists das selbe.
    Funktionen müssen einen Rückgabetyp (z.B. void, int oder etwas anderes) explizit angegeben haben.

    Wenn du mir mitteilst, ob du in C oder C++ schreiben möchtest, kann ich den Thread entweder ins richtige C-Forum verschieben oder wir können dir hier mit ordentlichem C++ weiterhelfen 🙂



  • lattemann schrieb:

    fwrite(BenDat,sizeof(struct  Pay), sizoef(BenDat),f);
    

    Wechstaben verbuchselt :p
    Muss heißen sizeof, is klar, wa.



  • lattemann schrieb:

    Während sich die anderen wegen C, C++, oder C# Grundsätzen fusselig labern, gebe ich dir schonmal ein paar Tips:

    Die wenn du die anderen Beiträge gelesen hättest nicht funktionieren können.

    lattemann schrieb:

    Wie sieht dein AnsiString Typ aus? char* konstanter Länger oder watt?

    AnsiString ist wie gesagt ein Datentyp des BCB (Genauer: Eine Klasse der VCL-Bibliothek).



  • asc schrieb:

    ... wenn du die anderen Beiträge gelesen hättest nicht funktionieren können.

    die anderen? das gefeilsche um den rückgabetypen? nee, ne.
    bisher habe ich diesbezüglich nur einen brauchbaren, den von Old MacDonald gesehen.

    @Mathiable:
    Hol dir für jeden Structmember den Zeiger auf die Daten, ermittle die Anzahl der Bytes, hau das in die Datei rein und gut ist.
    Beim AnsiString bin ich mir gerade nicht so sicher, ob man den Zeiger so bekommt:
    AnsiString Name;
    char* p = Name.c_str();
    Gruß,
    jepp.



  • die anderen? das gefeilsche um den rückgabetypen? nee, ne.
    bisher habe ich diesbezüglich nur einen brauchbaren, den von Old MacDonald gesehen.

    Aber dein Vorschlag wäre sogar noch eine Verschlimmbesserung gewesen - der hätte nämlich glatt einen Bufferoverrun noch zusätzlich erzeugt. 🙄

    Hol dir für jeden Structmember den Zeiger auf die Daten, ermittle die Anzahl der Bytes, hau das in die Datei rein und gut ist.
    Beim AnsiString bin ich mir gerade nicht so sicher, ob man den Zeiger so bekommt:
    AnsiString Name;
    char* p = Name.c_str();

    Viel Spaß. Denn wie du die Zeichenketten variabler Länge wieder korrekt auslesen willst, hast du noch nicht gesagt; zumindest nicht eindeutig genug, dass es Mathiable versteht.



  • Old McDonald schrieb:

    Aber dein Vorschlag wäre sogar noch eine Verschlimmbesserung gewesen - der hätte nämlich glatt einen Bufferoverrun noch zusätzlich erzeugt. 🙄

    ich schrieb, dass man u.u. einzeln speichern muss und habe nach dem datentypen gefragt 🙄

    Old McDonald schrieb:

    Viel Spaß. Denn wie du die Zeichenketten variabler Länge wieder korrekt auslesen willst, hast du noch nicht gesagt; zumindest nicht eindeutig genug, dass es Mathiable versteht.

    wie willst du denn beurteilen, was er versteht und was nicht 🙄



  • Das hier:

    fwrite(BenDat,sizeof(struct  Pay), sizeof(BenDat),f);
    

    Erzeugt einen Pufferüberlauf. Wenn Pay ein POD wäre, müsste es so lauten:

    fwrite(BenDat,sizeof(BenDat[0]), sizeof(BenDat)/sizeof(BenDat[0]),f);
    

    Aber lassen wir das - es ändert eh nichts daran, dass es falsch ist 🙂

    wie willst du denn beurteilen, was er versteht und was nicht 🙄

    Das kann ich nicht - aber ich kann es vermuten. Je nachdem, wie man deine Beschreibung liest, wie die Struktur in die Datei geschrieben werden soll, kommt entweder totaler Murks raus oder etwas, dass man wieder auslesen kann. Warum? Weil du nicht eindeutig dazugeschrieben hast, dass man auch noch die Länge der Zeichenkette mitspeichern muss oder die Zeichenkette mit '\0' terminieren muss. Die Beschreibung ist so einfach zu schwammig oder unvollständig.
    Naja, jetzt abwarten, bis sich Mathiable wieder meldet 🙂



  • Old McDonald schrieb:

    Das hier:

    fwrite(BenDat,sizeof(struct  Pay), sizeof(BenDat),f);
    

    Erzeugt einen Pufferüberlauf.

    Auch du Scheiße. Da haddu recht, was bin ich doch für eine Schlampe :D, da hab ich gepennt.

    Den Teiler habe ich ganz vergessen!
    Korrekt wäre in der Tat gewesen:

    fwrite ( BenDat, sizeof( struct Pay ), sizeof( BenDat )/sizeof(struct Pay), fp);
    

    für die sogenannten PODs. -> hier kein rolleyes <- 🙂



  • lattemän schrieb:

    Old McDonald schrieb:

    Das hier:

    fwrite(BenDat,sizeof(struct  Pay), sizeof(BenDat),f);
    

    Erzeugt einen Pufferüberlauf.

    Auch du Scheiße. Da haddu recht, was bin ich doch für eine Schlampe :D, da hab ich gepennt.

    Den Teiler habe ich ganz vergessen!
    Korrekt wäre in der Tat gewesen:

    fwrite ( BenDat, sizeof( struct Pay ), sizeof( BenDat )/sizeof(struct Pay), fp);
    

    für die sogenannten PODs. -> hier kein rolleyes <- 🙂

    Benutze in sizeof bitte immer Ausdrücke und keine Typbezeichner, wenn BenDat jemals kein Array von Pays mehr ist, dann ist dein Code falsch, während der von Old McDonald weiterhin das richtige tut.



  • Tippgeber schrieb:

    Benutze in sizeof bitte immer Ausdrücke und keine Typbezeichner, wenn BenDat jemals kein Array von Pays mehr ist, dann ist dein Code falsch, während der von Old McDonald weiterhin das richtige tut.

    Ja, das mach Sinn.



  • Schon mal vielen dank für die Mühen, dachte das Problem sei schneller gelöst. 🙂

    Ich habe es nun auch mit dem Teiler versucht, aber das Programm stürzt desswegen ab. Aber es sei ja so oder so falsch, wollte es nur mal ausprobieren.

    Viel Spaß. Denn wie du die Zeichenketten variabler Länge wieder korrekt auslesen willst, hast du noch nicht gesagt; zumindest nicht eindeutig genug, dass es Mathiable versteht.

    Mein wissen beschränkt sich anscheinend nur auf "Steinzeit C" und das auch nur Grundlegend, also ist es berechtigt anzunehmen das ich es nicht verstehe 😉

    Ich habe im Moment eine zwischenlösung, bei der der AnsiString zuerst in ein Char umgewandelt und dann abgespeichert wird. Das Funktioniert so weit, ist aber nicht gerade elegant gelöst...



  • Nein, verstehen wirst du's schon, aber an der Beschreibung von lattemann wirst du vermutlich scheitern 😉

    Das Problem ist, dass du auf Pay nicht wie auf rohem Speicher arbeiten kannst. AnsiString ist eine Klasse, die Speicher alloziert und freigibt und einen Zeiger auf den Speicher enthält. Kopierst du nur den rohen Speicher, hast du dann den Zeiger in der Datei, eigentlich willst du dann aber die Zeichenkette drin haben. Beim Einlesen wird dann einfach wieder irgendein alter Zeiger eingelesen. Wird das AnsiString-Objekt nun zerstört, will es den Speicher freigeben und es macht bumm.
    Also musst du alles einzeln speichern und nicht einfach den Speicherblock. Aber nur die Zeichenkette selbst zu schreiben, reicht natürlich nicht aus - du musst auch irgendwoher wissen, wie lang diese ist.

    Hm, also am besten schreibst du dir einige Funktionen, die das Lesen und Schreiben vornehmen. Der Schreibvorgang könnte z. B. mit C++-Streams so aussehen (Achtung! nicht durch einen Kompiler gejagt!):

    #include <ostream>
    // int schreiben
    void write(std::ostream &stream, int value)
    {
        stream.write(reinterpret_cast<const char*>(&value), sizeof(value));
    }
    
    // Zeichenkette (AnsiString) schreiben
    void write(std::ostream &stream, const AnsiString &value)
    {
        int length = value.Length(); // int AnsiString::Length() laut kurzer Googlesuche
        write(stream, length); // wir müssen die Länge speichern, um die Zeichenkette wieder korrekt auszulesen
        stream.write(value.c_str(), length); // und dann die Zeichenkette selbst natürlich auch noch
    }
    
    // Bezahlungsdaten schreiben
    void write(std::ostream &stream, const Pay &payment)
    {
        write(stream, payment.Name);
        write(stream, payment.PW);
        write(stream, payment.Strasse);
        write(stream, payment.Nr);
        // ...
    }
    
    // Funktion zum Schreiben von Feldern (dann brauchen wir keine Schleife in u_save() zu schreiben)
    template <typename T, std::size_t N>
    void write(std::ostream &stream, T (&array)[N])
    {
        for (std::size_t i = 0; i < N; ++i)
        {
            write(stream, array[i]);
        }
    }
    

    und voilà:

    #include <fstream>
    void u_save() 
    { 
        std::ofstream file("C:/Data.bin", std::ios_base::binary | std::ios_base::out);
    
        write(file, BenDat);
    }
    

    Der Lesevorgang sollte nun leicht zu schreiben sein.
    Wenn du bei den C-Streams bleiben willst, sollte es auch nicht allzu schwer sein, den Quelltext oben umzuschreiben (statt den std::ostream & -Parametern dann halt FILE* und statt stream.write(...) fwrite(..., stream) )

    Vielleicht überlegst du dir auch noch einmal, ob du nicht std::string nehmen willst - das hier ist das Standard-C++-Forum 😉



  • Vielleicht überlegst du dir auch noch einmal, ob du nicht std::string nehmen willst - das hier ist das Standard-C++-Forum 😉

    Ja hab ich mir schon gedacht. Hatte mal das Borland spezifische Forum gefunden, aber irgendwie wieder aus den Augen verloren. :p

    Dass mit dem schreiben funktioniert schon ganz gut, er schreibt eine 2 KB grosse datei mit den Daten. Das Lesen will allerdings noch nicht so recht. Er meckert immer, dass er einen Char erwartet und einen constant char bekommt.

    stream.read(reinterpret_cast<const char*>(&value), sizeof(value));
    


  • Was ist value für ein Typ und wieso willst du den casten? 😕



  • Hm, ja, in Konstanten kann man schlecht schreiben, oder? 🙂

    Ich schreibe dir mal eine read()-Funktion, die anderen wirst du wohl selbst hinbekommen:

    // int lesen
    void read(std::istream &stream, int &value)
    {
        stream.read(reinterpret_cast<char*>(&value), sizeof(value));
    }
    


  • Old McDonald schrieb:

    Hm, ja, in Konstanten kann man schlecht schreiben, oder? 🙂

    Macht sinn ja, hätte ich selbst drauf kommen müssen. :p

    Kompilieren kann er es jetzt, aber er liest nichts raus...

    ich hab auch irgendwie Zweifel an der einen Zeile:

    stream.write(value.c_str(), length); // und dann die Zeichenkette selbst natürlich auch noch
    

    kann es sein dass er length und value ständig wider überschreibt? und wenn nicht, woher soll er wissen welches length für welches value ist?



  • stream.write() ist schon einmal falsch - es müsste stream.read() heißen.

    AnsiString::c_str() ist eine merkwürdige Funktion. Sie gibt einen char* zurück, nicht einen const char*, wie man erwartet.
    Ohne mich mit C++-Builder und AnsiString auszukennen, rate ich mal ins Blaue hinein, wie es funktionieren könnte:

    void read(std::istream &stream, AnsiString &value)
    {
        int length;
        read(stream, length); // die Größe lesen
        value.SetLength(length); // der Puffer muss groß genug sein
        stream.read(value.c_str(), length); // und dann die Zeichenkette auslesen
    }
    


  • Wow, es hat sogar funktioniert. Danke tausendmal für die Geduld und Mühen. Ich spendier dir bei Gelegenheit mal ne runde. 😉


Anmelden zum Antworten