aus Textdatei arrays basteln



  • Das heißt es ist garnicht so toll auto dort zu verwenden, ich meine, ist das überhaupt definiert ob const oder nicht? Und sollte man einfach "manuell" const schreiben, wenn man sicher sein will, dass man da nix verändert?



  • Nathan schrieb:

    konstante Referenz

    😡 ALARM ALARM



  • hardware schrieb:

    Das heißt es ist garnicht so toll auto dort zu verwenden, ich meine, ist das überhaupt definiert ob const oder nicht? Und sollte man einfach "manuell" const schreiben, wenn man sicher sein will, dass man da nix verändert?

    auto ist dazu da, dass du das Denken dem Compiler überlassen kannst. Es ist immer sinnvoll, das Denken jemanden zu überlassen, der es zu 100% weiß. auto steht dann für den richtigen Datentypen. const hat mit auto nichts zu tun. const ist kein Datentyp.



  • out schrieb:

    Nathan schrieb:

    konstante Referenz

    😡 ALARM ALARM

    Ja, ja.
    Referenz auf const.
    🙄 😉



  • Hallo,

    danke für Eure Beiträge!

    Das meine while-Schleife mit der != eof() nicht schön ist, verstehe ich. Habe dafür aber gerade noch keine Alternative gefunden, denn ich muss meine Textdatei ja zeilenweise einlesen und brauche dafür eine Schleife?

    Ich habe versucht , die Datei in einen String einzulesen und diesen String dann in einen stringstream umzuwandeln, Fehlermeldung bekomme ich keine ,aber auch keine Ausgabe...

    Ich glaube das der letzte Schritt einfach ist, aber ich finde das ganze Thema schwierig und stehe da gerade auf dem Schlauch...

    int main()
    {
    string s;
    ifstream namendatei; // liegt im verzeichnis
    namendatei.open("namen.txt",ios_base::in); //oeffne textdatei mit namen
    
    stringstream ss(s);
    
    vector<DataEntry> data; //Vektor data der Klasse DataEntry angelegt
    
    while(!namendatei.eof()) //solange noch daten vorliegen
    {
    getline(namendatei,s); //liess  eine zeile ein
    
    //stringstream ss("1,Max,Mustermann\n2,Rolf,Muster\n3,Pia,Muster");
      for(DataEntry entry; ss >> entry;)
        data.push_back(entry);
    
    } 
      // Testausgabe:
      for(const DataEntry& entry: data)
        std::cout << entry << '\n';
    
        return 0;
    }
    


  • int main()
    {
        ifstream namendatei("namen.txt");
        vector<DataEntry> data;
        for(string s; getline(namendatei,s); )
        {
            stringstream ss(s);
            for(DataEntry entry; ss >> entry; )
                data.push_back(entry);
        } 
        for(const DataEntry& entry: data)
            std::cout << entry << '\n';
    
        return 0;
    }
    

    sollte funktionieren

    LG


  • Mod

    fischldi schrieb:

    Das meine while-Schleife mit der != eof() nicht schön ist, verstehe ich. Habe dafür aber gerade noch keine Alternative gefunden, denn ich muss meine Textdatei ja zeilenweise einlesen und brauche dafür eine Schleife?

    Nicht unschön, sondern schlichtweg falsch. Wenn das in deinem Lehrbuch so stand (kommt leider vor), dann schmeiß es weg. Wenn du einen Fehler beim Lesen hast, dann verarbeitest du hier Mülldaten, erst dann folgt deine Prüfung ob das Lesen erfolgreich war. Und nicht einmal das, denn du prüfst nur auf Dateiende, bei anderen Fehlern hättest du eine feine Endlosschleife der Müllverarbeitung.

    Lesen läuft in C++ (und anderen C-artigen Sprachen) immer so ab:
    -einlesen
    -prüfen
    -verarbeiten

    Einen Stream kann man ganz einfach auf einen Fehlerzustand prüfen (und zwar alle möglichen Fehler, nicht nur eof!), indem man ihn in einem boolschen Kontext auswertet:

    int i;
    cin >> i;
    if (cin) ... // erfolgreich?
    

    Schönerweise geben fast alle Leseaktionen in C++ den Stream selbst zurück, so dass man die Leseaktion und die Prüfung schick zusammen fassen kann:

    int i;
    if (cin >> i) ... // erfolgreich?
    

    So etwas kann man dann naheliegenderweise auch als Abbruchbedingung für Schleifen benutzen. Oft gesehene Konstrukte:

    int i;
    while (cin >> i)
    {
      // i verarbeiten
    }
    
    // oder
    
    for(int i; cin >> i; )
    {
      // i verarbeiten
    }
    

    Dies ist ebenfalls etwas, das in einem Lehrbuch erklärt gehört, wenn das nicht drin steht, dann hat das irgendjemand geschrieben, der vor 30 Jahren Mal Pascal gelernt hat (da geht das tatsächlich so wie du es versuchst) und denkt, C++ wäre wenn er BEGIN und END durch { und } ersetzt.



  • SeppJ hat die perfekte Lösung bereits gepostet. Wieso nimmst du diese nicht und versuchst alles nachzuvollziehen? Dann hast was gutes gelernt. Wenn was an seinem Code nicht verstehst kann man auf jene Zeile ja eingehen hier.



  • wie cool ist das denn..danke!!

    Das mit der falschen Abbruchbedingung habe ich tatsächlich aus einem etwas älteren Lehrbuch...gut..daraus werde ich in Zukunft wohl nichts mehr übernehmen.

    Vielen dank!


  • Mod

    out schrieb:

    SeppJ hat die perfekte Lösung bereits gepostet. Wieso nimmst du diese nicht und versuchst alles nachzuvollziehen? Dann hast was gutes gelernt. Wenn was an seinem Code nicht verstehst kann man auf jene Zeile ja eingehen hier.

    Oh, der Thread ist das. Hatte ich doch recht in Erinnerung, dass ich so eine Frage vor einer Weile schon einmal beantwortet habe 🙂 .

    Dann weise ich nochmal auf den Beitrag hin:
    http://www.c-plusplus.net/forum/p2374094#2374094

    Da drin ist alles was du brauchst mit Erklärung. Sogar mit Beispiel. Du musst nur den stringstream durch deinen Dateistream tauschen und schon hast du sogar deine Ausgangsfrage beantwortet und musst dafür nur 1-2 Zeilen ändern.



  • Guten Abend,

    Ich bräuchte noch einmal eure Hilfe...ich würde gerne mit Hilfe des Vektors (wie man es mit arrays macht hätte ich gewusst) einen SQLite Befehl "füllen"...

    rc = sqlite3_open("test.db", &db);
    rc=sqlite3_exec(db,"insert into person (personID,name,vorname) values ( ?????? );",callback,0,&zErrMsg);

    Ich habe es folgendermassen probiert:

    int main()
    {
        ifstream namendatei("namen.txt");
        vector<DataEntry> data;
        for(string s; getline(namendatei,s); )
        {
            stringstream ss(s);
            for(DataEntry entry; ss >> entry; )
            rc=sqlite3_exec(db,"insert into person (personID,name,vorname) values (data.id,data.last_name,dta.first_name );",callback,0,&zErrMsg); 
                data.push_back(entry);
    
        }
        for(const DataEntry& entry: data)
       cout << entry << '\n';
    
        return 0;
    }
    

    Damit soll dann eine Tabelle in meiner Datenbank gefüllt werden...ich komm da einfach nicht weiter.... 😕



  • Und wieso genau verwendest du da jetzt einen stringstream? 🙄



  • Das ist eine gute Frage...weil ich es nicht besser gewusst habe.... 😞



  • Meine Textdatei hat schon genau die Form die ich für die Tabelle brauchen kann..



  • Funktioniert der Quellcode von SeppJ nun nicht mehr oder wie? Was hast an der Textdatei geändert, wie schaut sie nun aus? Was willst du eigentlich erreichen wo liegt nochmal das Problem? Dachte alles wäre schon geklärt:D Wir brauchen harte Fakten und keine Codefetzen.



  • out schrieb:

    Funktioniert der Quellcode von SeppJ nun nicht mehr oder wie? Was hast an der Textdatei geändert, wie schaut sie nun aus? Was willst du eigentlich erreichen wo liegt nochmal das Problem? Dachte alles wäre schon geklärt:D Wir brauchen harte Fakten und keine Codefetzen.

    Guten Morgen,

    doch...der Code funktioniert einwandfrei...zu Beginn wollte ich mit Arrays arbeiten, doch ein Vector scheint hier geeigneter.Vielleicht kann ich meine Frage anders formulieren...meine Textdatei sieht so aus (id,name,vorname),meine SQLite Datenbank hat in einer Tabelle selbige Spalten (id,name,vorname).
    Nun würde ich gerne mit einer for-Schleife durch den Vector "laufen" und die id, den vornamen und den nachnamen in die Tabelle "schieben", das geht mit dem SQLite_exec Befehl.

    Ich weiss nur gerade nicht wie man durch einen Vector läuft...

    Idee:

    for-Schleife (läuft sooft durch wie Datensätze in Textdatei vorhanden)
    SQLite_exec(insert into person(id,vorname,nachname) values (id aus vector, name aus vector,nachname aus vector).

    Wie kann ich soetwas realisieren?

    Wäre sehr dankbar über hilfe 🙂
    😕



  • Evtl. sollte der Thread gespalten werden - ich kann nicht erkennen, ob C++ oder sqlite das Problem ist.

    Zum sqlite-Teil: Du bereitest ein Statement vor, verknüpfst dessen Platzhalter mit Deinen Werten und führst das Statement aus.
    Geht sicherlich auch mit dem "Convenience-Wrapper" sqlite3_exec() allerdings IMHO auf Kosten der Leserlichkeit.

    Ein Beispiel wie sowas aussehen könnte: (Z. 35-49)

    #include <fstream>
    #include <iostream>
    #include <iterator>
    #include <memory>
    #include <string>
    
    #include <sqlite3.h>
    
    struct person{
      int id_;
      std::string name_, firstname_;
    };
    
    std::istream& operator>>(std::istream& in, person& p){
      return in >> p.id_ >> p.name_ >> p.firstname_;
    }
    
    std::ostream& operator<<(std::ostream& out, const person& p){
      return out << p.id_ << ": " << p.name_ << ", " << p.firstname_;
    }
    
    using sqlite_db =  std::unique_ptr<sqlite3, int(*)(sqlite3*)>;
    sqlite_db open(){
      sqlite3* tmp;
      sqlite3_open(":memory:", &tmp);
      return {tmp, sqlite3_close};
    }
    
    void create(const sqlite_db& db){
      const char* sql = "CREATE TABLE person"
                        "(id INTEGER, name TEXT, firstname TEXT)";
      sqlite3_exec(db.get(), sql, nullptr, nullptr, nullptr);
    }
    
    template<typename InputIterator>
    void to_db(InputIterator first, InputIterator last, const sqlite_db& db){
      const char* sql = "INSERT INTO person VALUES(?, ?, ?)";
      sqlite3_stmt* pstmt; 
      sqlite3_prepare_v2(db.get(), sql, -1, &pstmt, nullptr);
      while(first!=last){
        sqlite3_bind_int(pstmt, 1, first->id_);
        sqlite3_bind_text(pstmt, 2, first->name_.c_str(), -1, SQLITE_STATIC);
        sqlite3_bind_text(pstmt, 3, first->firstname_.c_str(), -1, SQLITE_STATIC);
        sqlite3_step(pstmt);
        sqlite3_reset(pstmt);
        ++first;
      }
      sqlite3_finalize(pstmt);
    }
    
    template<typename OutputIterator>
    void from_db(OutputIterator to, const sqlite_db& db){
      const char* sql = "SELECT * FROM person";
      sqlite3_stmt* pstmt; 
      sqlite3_prepare_v2(db.get(), sql, -1, &pstmt, nullptr);
      while(sqlite3_step(pstmt)==SQLITE_ROW){
        const person tmp{
          sqlite3_column_int(pstmt, 0),
          reinterpret_cast<const char*>(sqlite3_column_text(pstmt, 1)),
          reinterpret_cast<const char*>(sqlite3_column_text(pstmt, 2))
        };
        *to++=tmp;
      }
      sqlite3_finalize(pstmt);
    }
    
    int main(){
      auto db = open();
      create(db);
      std::ifstream file("data.txt");
      using iiter = std::istream_iterator<person>;
      to_db(iiter{file}, iiter{}, db);
      using oiter = std::ostream_iterator<person>;
      from_db(oiter{std::cout, "\n"}, db);
    }
    

    data.txt:

    1 Wurble Furble
    2 Mustermann Franz
    3 Mustermann Susanne
    

    Die Lernkurve ist ziemlich steil, wenn Du noch Anfänger bist, vorallem weil Du auch ein C Verständnis brauchst, um sqlite zu bändigen.


Anmelden zum Antworten