Datei zeilenweise auslesen und in einem Vektor abspeichert, speichert Werte nur aus der ersten Zeile



  • Hallo,

    ich arbeite mich gerade in C** ein mit Hilfe des Buches "Der C++ Programmierer" und wollte jetzt ein Projekt selber mal umsetzen. Ich schreiben einen Sudoku Löser. Die Funktionen werteEingeben und anzeigen klappen wunderbar. Der Konstruktor klappt auch super. Probleme habe ich allerdings mit dem überladenen Konstruktor.

    Sudoku::Sudoku(std::string s) {
        std::string zeile;
        std:: vector<int> temp;
        std::fstream quelle(s);
        int x;
        if(!quelle) {
            std::cerr << "Öffnen nicht möglich!\n";
        }
    
        while (quelle) {
            std::getline(quelle,zeile);
            for (int j=0; j<9; ++j) {
                x=zeile[j] - '0';
                temp.push_back(x);
            }
            elemente.push_back(temp);
        }
    }
    

    Mit dem String s wird die Datei übergeben, in der die vorhandenen Zahlen stehen. Wenn ich mir dann elemente anzeigen lasse, sieht es so aus.

    0000800090
    0000800090
    0000800090
    0000800090
    0000800090
    0000800090
    0000800090
    0000800090
    0000800090
    0000800090
    

    Die eingelesene Datei sieht allerdings so aus.

    000080009
    000426130
    000901506
    200890974
    309060080
    000294000
    056310000
    000000807
    084052010
    

    Es wird immer nur die erste Zeile abgespeichert. Die Funktion anzeigen() funktioniert wie sie soll. Wenn ich die Werte per Hand, über die Funktion werteEingaben(), eingebe werden sie korrekt angezeigt.

    Hier mal der restliche Quellcode

    main.cpp

    #include "sudoku.h"
    
    int main() {
        Sudoku s("sudoku.txt");
        //s.werteEingeben();
        s.anzeigen();
        //s.berechnen();
        //s.anzeigen();
    }
    

    sudoku.h

    #ifndef SUDOKU_H
    #define SUDOKU_H
    #include <vector>
    #include <string>
    
    class Sudoku {
    public:
        Sudoku();
        Sudoku(std::string s);
        void werteEingeben();
        void anzeigen();
        void berechnen();
    private:
        std::vector<std::vector<int>> elemente;
        bool ueberpruefen(int x, int y, int z);
        std::vector<int> feldBauen(int x, int y);
    };
    #endif
    

    sudoku.cpp

    #include "sudoku.h"
    #include <iostream>
    #include <vector>
    #include <fstream>
    
    Sudoku::Sudoku() {
        std:: vector<int> temp;
        for (int i=0; i<9; ++i) {
            for (int j=0; j<9; ++j) {
                int x=0;
                temp.push_back(x);
            }
            elemente.push_back(temp);
        }
    }
    
    Sudoku::Sudoku(std::string s) {
        std::string zeile;
        std:: vector<int> temp;
        std::fstream quelle(s);
        int x;
        if(!quelle) {
            std::cerr << "Öffnen nicht möglich!\n";
        }
    
        while (quelle) {
            std::getline(quelle,zeile);
            for (int j=0; j<9; ++j) {
                x=zeile[j] - '0';
                temp.push_back(x);
            }
            elemente.push_back(temp);
        }
    }
    
    void Sudoku::anzeigen() {
        for (int i=0; i<elemente.size(); ++i) {
            for (int j=0; j<elemente.size(); ++j) {
                std::cout << elemente[i][j];
            }
            std::cout << '\n';
        }
        std::cout << elemente.size() << '\n';
    }
    
    void Sudoku::werteEingeben() {
        bool ende = 1;
        do {
            anzeigen();
            int vektor, feld, wert;
            std::cout << "Wert eingeben: ";
            std::cin >> vektor >> feld >> wert;
            if(vektor==0) {
                if(feld==0) {
                    if(wert==0) {
                        break;
                    }
                }
            }
            if(vektor<=9) {
                if(feld<=9) {
                    if(wert<=9) {
                        elemente[vektor-1][feld-1]=wert;
                        std::cout << "\033[2J\033[1;1H"; // Bildschirm löschen
                    }
                    else {
                        std::cout << "Falsche Eingabe\n";
                    }
                }
                else {
                    std::cout << "Falsche Eingabe\n";
                }
            }
            else {
                std::cout << "Falsche Eingabe\n";
            }
        } while (ende);
        std::cout << "\033[2J\033[1;1H";
    }
    
    void Sudoku::berechnen() {
        // TODO
    }
    
    bool Sudoku::ueberpruefen(int x, int y, int z) {
        std::cout << "Überprüfen\n";
        std::vector<int> feld=feldBauen(x,y);
        bool vorhanden=0;
        for(int ui=0; ui<9; ++ui) {
            if(elemente[ui][y]==z) {
                vorhanden=1;
            }
            std::cout << "x\n";
        }
        for(int uj=0; uj<9; ++uj) {
            if(elemente[x][uj]==z) {
                vorhanden=1;
            }
            std::cout << "y\n";
        }
        for(int uk=0; uk<9; ++uk) {
            if(feld[uk]==z) {
                vorhanden=1;
            }
            std::cout << "f\n";
        }
        std::cout << "Ende überprüfen\n";
        return vorhanden;
    }
    
    std::vector<int> Sudoku::feldBauen(int x, int y) {
        std::cout << "Feldbauen\n";
        int anfangx, endex, anfangy, endey;
        int zaehler {0};
        std::vector<int> feld(9);
        if(x>=0 && x<=2) {
            anfangx=0;
            endex=2;
        }
        else if(x>=3 && x<=5) {
            anfangx=3;
            endex=5;
        }
        else if(x>=6 && x<=8) {
            anfangx=6;
            endex=8;
        }
        if(y>=0 && y<=2) {
            anfangy=0;
            endey=2;
        }
        else if(y>=3 && y<=5) {
            anfangy=3;
            endey=5;
        }
        else if(y>=6 && y<=8) {
            anfangy=6;
            endey=8;
        }
        for(int fi=anfangx; fi<=endex; ++fi) {
            for(int fj=anfangy; fj<=endey; ++fj) {
                std::cout << "Feldzuweisen\n";
                std::cout << fi << " " << fj << " " << zaehler << '\n';
                elemente[fi][fj]=feld[zaehler];
                zaehler += 1;
                std::cout << feld[zaehler] << '\n';
            }
        }
    }
    


  • Wie lang ist temp nach jeder gelesenen Zeile?



  • Oh man 😡

    Nachdem ich mir die Länge angeschaut habe. Habe ich festgestellt, dass temp immer länger wird

    9
    18
    27
    36
    45
    54
    63
    72
    81
    90
    

    mit temp.clear() ist das Problem behoben 😃

    Sudoku::Sudoku(std::string s) {
        std::string zeile;
        std:: vector<int> temp;
        std::fstream quelle(s);
        int x;
        if(!quelle) {
            std::cerr << "Öffnen nicht möglich!\n";
        }
    
        while (quelle) {
            std::getline(quelle,zeile);
            for (int j=0; j<9; ++j) {
                x=zeile[j] - '0';
                temp.push_back(x);
            }
            std::cout << temp.size() << '\n';
            elemente.push_back(temp);
            temp.clear();
        }
    }
    

    Danke! 👍



  • Das mit getline und string kannst Du Dir sparen (steht das so in 'Der C++ Programmierer'?)
    Lese doch einfach die Ziffern ein, dann liest Du die letzte Zeile auch nicht mehr doppelt

    Sudoku::Sudoku(std::string s) {
        std::fstream quelle(s);
        if(!quelle.is_open()) {
            std::cerr << "Öffnen nicht möglich!\n";
        }
        while( quelle ) {
            std::vector<int> temp;
            char x;
            for( int i=0; i<9 && quelle >> x; ++i )
                temp.push_back( int(x - '0') );
            if( quelle )
                elemente.push_back( std::move(temp) );
        }
    }
    

    Gruß
    Werner



  • Hallo,

    ja das wird, bis Kapitel fünf zumindest, so gezeigt. Danke für deine Anmerkung. Werde sie umsetzen.



  • weit vorher in Kap 1.10 wird >> erläutert und dass man das auch für Dateien nutzen kann.

    @Werner: da steht move. Wozu genau?
    Performance vielleict? Wieviel %?



  • nochfragen schrieb:

    da steht move. Wozu genau?
    Performance vielleict? Wieviel %?

    Ja wg. Performance. Der Unterschied zur Implementierung ohne std::move, besteht darin, dass in diesem Fall der vector temp noch einmal kopiert wird. Wenn Du fragst "Wieviel %" kann ich nur sagen: selber nachmessen!
    In diesem Codeschnipsel kommen auf eine gesparte Kopie eines vector 9mal Lesen eines Zeichen und Speichern im vector . Ich vermute mal, dass sich das prozentual kaum bemerkbar macht. Aber es ist letztlich auch ein Frage des Stils.

    Nachtrag:
    nach einem move sollte die Quelle (hier temp ) IMHO auch nicht mehr benutzt werden (ich weiß gar nicht was der Standard dazu sagt?). D.h. temp ist dann 'weg'. Damit unterstreiche ich hier auch, dass es sich mit temp um eine lokale Variable handelt, die nur innerhalb des Scopes der Schleife existiert. Ganz im Gegensatz zum ursprünglichen Code von bruhial. Einer der Fehler, die im ursprünglichen Code gemacht wurden, entstand ja nur aus der 'Wiederverwendung' von temp .
    Auch durchaus erfahrene Programmierer neigen in bestimmten Fällen dazu, Variablen, die nur innerhalb einer Schleife genutzt werden, außerhalb zu definieren, auch wenn das nicht nötig ist. Das nur weil der optische Effekt einer vermeidlichen Wiederverwendung dazu verleitet. Man nehme alles aus einer Schleife heraus was geht, um sie 'schneller' zu machen.
    In der Praxis handelt man sich nach meiner Erfahrung mehr Probleme dabei ein, als dass da irgendwie ein positiver Effekt bei der Performance entsteht.

    Gruß
    Werner



  • danke für die erklärung. leuchtet ein.


Log in to reply