Speicher allokieren, was geht schief?



  • Tag,

    ich habe eine Methode in welcher ich Daten aus
    einer sqlite3 Datenbank auslese und weiterverarbeite:

    char** Textverwaltung::gibKurzbeschreibung()
    {
       int anzahlTexte;
       // Anzahl der Texte ermitteln
       sqlQuery = "SELECT anzahltexte FROM festwerte";
       abfrageChar = db->readUnformatted(sqlQuery);
       abfrageString = abfrageChar[1];
       anzahlTexte = abfrageString.ToInt();
       // Speicher allokieren
       char** zurueckgeben = new char*[anzahlTexte+1];
       zurueckgeben[0] = new char[abfrageString.Length()]; 
       zurueckgeben[0] = abfrageString.c_str();
    
       // Texte auslesen
       sqlQuery = "SELECT * FROM texte ORDER BY id";
       abfrageChar = db->readUnformatted(sqlQuery);
    
       // Daten aus der Datenbank formatieren
       for(int i=0; i<anzahlTexte*2; i=i+2)
       {
    	  abfrageString = "ID: ";
    	  abfrageString = abfrageString + abfrageChar[i+2]; // Hier <- !!!
    	  abfrageString = abfrageString + " Text: ";
    	  abfrageString = abfrageString + abfrageChar[i+3];
    	  int blub = abfrageString.Length();
    	  zurueckgeben[(i/2)+1] = new char[abfrageString.Length()];
    	  zurueckgeben[(i/2)+1] = abfrageString.c_str();
       }
    
       db->clearTable();
       return zurueckgeben;
    }
    

    Das Problem ist dass beim Speicher allokieren irgendwas schief geht,
    wenn er über die markierte Zeile in der for Schleife gelaufen ist,
    ändert er auch den Wert in zurueckgeben[0] auf den Wert in
    abfrageChar[i+2].

    Sieht jemand den Fehler?
    Danke schonmal 😉

    Gruß,

    Max



  • Evtl hilft i<anzahlTexte*2-1 ?



  • Nein, hilft nicht da der Wert in jedem Durchlauf, also
    auch schon im ersten Überschrieben wird.
    Die Schleifenbedingung sollte so auch stimmen,
    setzt sich so zusammen:

    id | inhalt
    -----------
    0  | blub
    1  | möp
    2  | joa
    

    So sieht im Prinzip die Tabelle aus.
    In dem 2-Dimensionalen char Array ist
    nachher

    abfrageChar[0] == "id"
    abfrageChar[1] == "inhalt"
    
    abfrageChar[2] == 0
    
    // etc...
    

    Ich laufe mit der Schleife 1x durch alle ausgelesenen
    Texte, *2 ist nur weil ich ja immer i=i+2 mache.
    In der Schleife selber +2 / +3 ist um die Überschriften
    zu überspringen.

    Gruß,

    Max



  • Der Fehler ist in Zeile 26.



  • Gut, aus dem Grund wird der Speicher ja auch schon in
    Zeile 22 überschrieben...



  • Welchen Typ haben denn deine verwendeten Variablen so?



  • char** abfrageChar
    String abfrageString

    sonst gibts glaube ich keine die unbekannt wären
    in der Methode.

    Achja, hinter der db->readUnformatted(...)
    Methode steckt eine sqlite3 Funktion die den Speicher für
    das abfrageChar Array allokiert, das sollte also stimmen,
    wenn nicht haben außer mir noch ein paar Leute Probleme damit :>



  • ok, aber das hier versteh ich noch nicht so ganz:

    abfrageChar[0] == "id"
    abfrageChar[1] == "inhalt"
    abfrageChar[2] == 0
    
    // etc...
    

    Ist abfrageChar[2]=="0" oder NULL? Und abfrageChar[3]=="blub" ?

    Und gibt's einen Grund, warum du nicht "richtige" Arrays benutzt, z.B. std::vector oder so? Oder einfach so? 😉



  • zurueckgeben[(i/2)+1] = new char[abfrageString.Length()];
    zurueckgeben[(i/2)+1] = abfrageString.c_str();
    

    Hier ist m.E. ein Fehler: Der Zeiger auf den allokierten Speicher ist doch weg, wenn du ihn sofort überschreibst. Du solltest den Inhalt von abfrageString eher reinkopieren, als den Zeiger darauf zu setzen.



  • Hmmm verstehe ich dich richtig:

    zurueckgeben[(i/2)+1] = abfrageString.c_str();

    Damit setze ich den Zeiger zurueckgeben[(i/2)+1] auf
    die Adresse vom abfrageString?

    Wenn das wirklich so ist, wie kopier ich dann die Daten?



  • blub² schrieb:

    Wenn das wirklich so ist, wie kopier ich dann die Daten?

    Ich bin mir schon ziemlich sicher, dass dem so ist 😉 Kopieren kannst du z.B. so:

    zurueckgeben[(i/2)+1] = new char[abfrageString.Length()+1]; // +1 wegen Nullterminiert
    strcpy( zurueckgeben[(i/2)+1], abfrageString.c_str() );
    

    Aber ich denke wirklich, dass dir die Sachen aus der C++-Standardbibliothek vieles einfacher machen würden. Hier mal kurz angerissen, wie die Funktion dann aussehen würde:

    vector<string> Textverwaltung::gibKurzbeschreibung()
    {
        // Bis Kommentar "Speicher allokieren" wie gehabt
    
        vector<string> zurueckgeben;
        zurueckgeben.push_back( abfrageString );
    
        // "Texte auslesen" wie gehabt
    
        // Daten aus der Datenbank formatieren
        for(int i=0; i<anzahlTexte*2; i=i+2)
        {
            string s = string("ID: ") + abfrageChar[i+1] + " Text : " + abfrageChar[i+3];
            zurueckgeben.push_back( s );
        }
    
        ...
    }
    


  • Danke für den Beispielcode aber tut leider nicht mit
    strcpy (hätte ich nun wirklich auch selber draufkommen können -.-)

    @Standardbibliothek
    Ja, ich programmiere erst seit einem halben Jahr aktiv,
    bin durch die Schule dazu gekommen...
    und dort müssen wir halt Borland benutzen 🙄
    Sitze aber grade am C++ Primer um mir mal das ganze Standard Zeugs anzueignen
    und will eigentlich auch eher in Richtung WinAPI und Standardbibliothek,
    weg von dem VCL Zeug...

    Gruß,

    Max



  • push, bevors auf Seite 2 verschwindet



  • blub² schrieb:

    push, bevors auf Seite 2 verschwindet

    Es ist eine Unsitte seinen Thread zu pushen nur weil nicht innerhalt noch nichtmal eines Tages keine Antworten kommen. Du bist hier nicht alleine im Forum.



  • blub² schrieb:

    Sitze aber grade am C++ Primer um mir mal das ganze Standard Zeugs anzueignen und will eigentlich auch eher in Richtung WinAPI und Standardbibliothek,
    weg von dem VCL Zeug...

    Du kannst auch mit einem Borland Compiler Standard-C++Programme schreiben. Gerade der aktuelle (BCB2007) ist da schon auf einem guten Weg. Du musst ja die VCL nicht verwenden. Warum du gerade WinAPI verwendet willst erschließt sich mir nicht gerade. Warum willst du dir es unnötig kompliziert machen?



  • Was funktioniert denn noch nicht oder noch dasselbe? Wie sieht mittlerweile der Quellcode aus?



  • Braunstein schrieb:

    blub² schrieb:

    Sitze aber grade am C++ Primer um mir mal das ganze Standard Zeugs anzueignen und will eigentlich auch eher in Richtung WinAPI und Standardbibliothek,
    weg von dem VCL Zeug...

    Du kannst auch mit einem Borland Compiler Standard-C++Programme schreiben. Gerade der aktuelle (BCB2007) ist da schon auf einem guten Weg. Du musst ja die VCL nicht verwenden. Warum du gerade WinAPI verwendet willst erschließt sich mir nicht gerade. Warum willst du dir es unnötig kompliziert machen?

    Ähm also WinAPI ist vlt komplizierter, aber vonwegen Borland,
    Die ganzen Objekte, TListBox, RichEdit etc... erwarten alle nen AnsiString
    d.h. ich muss immer den std::string in nen c String konvertieren und dann
    übergeben. Das geht ja sogar noch ganz gut aber wenns Rückgabewerte sind
    muss ich auch noch mit ner Hilfsvariable arbeiten 😞

    int anzahlTexte;
       // Anzahl der Texte ermitteln
       sqlQuery = "SELECT anzahltexte FROM festwerte";
       abfrageChar = db->readUnformatted(sqlQuery);
       abfrageString = abfrageChar[1];
       anzahlTexte = abfrageString.ToInt();
       // Speicher allokieren
       char** zurueckgeben = new char*[anzahlTexte+1];
       zurueckgeben[0] = new char[abfrageString.Length()]; 
       zurueckgeben[0] = abfrageString.c_str();
    
       // Texte auslesen
       sqlQuery = "SELECT * FROM texte ORDER BY id";
       abfrageChar = db->readUnformatted(sqlQuery);
    
       // Daten aus der Datenbank formatieren
       for(int i=0; i<anzahlTexte*2; i=i+2)
       {
    	  abfrageString = "ID: ";
    	  abfrageString = abfrageString + abfrageChar[i+2];
    	  abfrageString = abfrageString + " Text: ";
    	  abfrageString = abfrageString + abfrageChar[i+3];
    	  zurueckgeben[(i/2)+1] = new char[abfrageString.Length()+1];
    	  strcpy(zurueckgeben[(i/2)+1], abfrageString.c_str());
    	  //zurueckgeben[(i/2)+1] = abfrageString.c_str();
       }
    
       db->clearTable();
       return zurueckgeben;
    

    Ist glaube ich immernoch recht gleich, wollte es heute Abend
    mal mit den Vektoren probieren, hab mich heute schon bissle
    eingelesen.
    Aber, selbst wenn es mit den Vectoren denn klappen sollte
    wüsste ich gern was hier falsch ist.

    Gruß,

    Max

    #edit:

    Ok, hab jetz ein Prob mit den std::string s

    folgende Zeile:

    sqlQuery = "UPDATE festwerte SET letzteid=" + toString(letzteID);
    

    folgender Fehler:

    [BCC32 Fehler] Textverwaltung.cpp(57): E2015 Mehrdeutigkeit zwischen 'toString<DataType>(const DataType &)' und 'Classes::toString'

    folgender Code ist hinter der toString Funktion:

    template<typename DataType>
    std::string toString(const DataType& value)
    {
      std::ostringstream output;
      output << value;
      return output.str();
    }
    

    Und ja, ich hab keine Ahnung was die Funktion genau macht, wie gesagt,
    Standardbibliothek erst seit 3 Tagen 😃
    Kann mir jemand sagen was hier schiefgeht? 🙂


Anmelden zum Antworten