aus Textdatei arrays basteln


  • Mod

    fischldi schrieb:

    Vielen dank,da ich schon sehr lange nichts mehr programmiert habe, gehe ich an die Sachen oft etwas zu umständlich ran. habe Dein Programm gerade ausprobiert, mein Compiler hat folgendes zurückgemeldet: "error: range-based ‘for’ loops are not allowed in C++98 mode"...das beziehet sich auf die Schleife in der main.

    Hast Du eien Idee warum er da meckert?

    Weil es range based 'for' Schleifen in C++98 nicht gibt 🙂 . Das gibt es erst seit C++11. Da dein Compiler das Konstrukt erkennt, kann er offensichtlich C++11. Es bleiben zwei Wege:
    -Du setzt du deinen Compiler in den C++11-Modus (das willst du kurz oder lang vermutlich sowieso). Was ist das für ein Compiler? GCC? Bei dem setzt du die Kommandozeilenoption -std=c++11 oder bei älteren Versionen (vor 2011) -std=c++0x .
    -Du schreibst den Code um. Er gibt alle Elemente in dem vector aus. Solltest du auch ohne range-based for hinbekommen, oder? Ist bloß mehr Schreibarbeit, weshalb ich es nicht so gemacht habe.



  • Hallo SeppJ,

    danke, Dein Tipp mit dem g++ Compiler hat geholfen , ich kann es kompilieren 🙂

    Das was Du mir geschrieben hast, klingt sehr nach dem was ich brauche!! Ich habe ja eine Textdatei in der die ganzen Datensätze liegen. Beim Versuch die Daten aus der Textdatei in das Programm einfliessen zu lassen, kam eine ellenlange Fehlermeldung.

    Ich habe es folgendermassen probiert:

    int main()
    {
    string s;
    
    ifstream namendatei; // Namensdatei iegt im verzeichnis
    namendatei.open("namen.txt",ios_base::in); //oeffne textdatei mit namen
    
    while(!namendatei.eof()) //solange noch daten vorliegen
    {
    getline(namendatei,s); //liess  eine Zeile ein
    cout << s;
    
      // Daten in Feld lesen:
      std::vector<DataEntry> data;
      for(DataEntry entry; s >> entry;)
        data.push_back(entry);
    } 
      // Testausgabe:
      for(const DataEntry& entry: data)
        std::cout << entry << '\n';
    
    return 0;
    }
    

    Hat das etwas mit dem ifstream zu tun? Aber dieses Format brauche ich doch um aus Textdatein zu lesen??

    Danke schonmal für eure Hilfe...wenn das geschafft ist bekomme ich den Rest alleine hin 🙂



  • Hi.

    -Schau dir mal RAII an. Dann weißt du, warum du kein namendatei.open brauchst.
    -Du musst nach einem Einelsevorgang prüfen, ob das Einlesen erfolgreich war. Also zwischen getline(namendatei,s) und cout << s; fehlt etwas.
    -Wenn du DataEntry ausgeben willst, musst du operator<< überladen.


  • Mod

    Du versuchst hier operator>> auf einen String und einen DataEntry anzuwenden, was irgendwie total sinnlos ist. Die Fehlermeldung sagt, dass es einen solchen Operator nicht gibt und schlägt dir alle möglichen Alternativen vor (daher ist die Meldung so lang).

    Du hättest einfach nur den Stringstream aus dem Beispiel durch deine Datei ersetzen brauchen, dann hätte alles gepasst. Das schöne am IO-Modell von C++ ist doch, dass die ganzen Streamtypen untereinander austauschbar sind. Alles was du jetzt zusätzlich zum Code hinzu gefügt hast macht das Programm kaputt:
    -Die Abbruchbedingung while(!eof) ist Schwachsinn. Das ist in keiner C-artigen Sprache richtig. Wo du das her hast, solltest du nicht weiter lesen. Derjenige, der dir das gezeigt hat, hat keine Ahnung.
    -Der ganze Punkt den ich machen wollte war doch, dass man die Formatierung zentral in die Lesefunktion packen sollte. Das getline in der main und der anschließende (falsche, s.o.) Versuch auf die Zeile die Lesefunktion anzuwenden ist gerade das, was hier vermieden werden sollte.



  • Mal eine Frage:

    Ist das hier

    for(const DataEntry& entry: data)
    

    Equivalent zu

    for(auto entry : data)
    

    oder gibt es da einen Unterschied und wenn ja, welcher?
    (Abgesehen vom syntaktischen)



  • Ja, einmal ist das eine konstante Referenz auf DataEntry, ein andermal decltype(*data.begin()), was nicht unbedingt eine konstante Referenz sein muss, sondern eher eine nicht konstante Referenz.



  • 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..


Anmelden zum Antworten