[GELÖST] Probleme beim Einlesen/Ausgeben (fstream, Stringarray)



  • Morgen,

    ich bastel mir gerade einen ganz simplen Parser, der aus einer Datei folgender Bauweise ein Stringarray erzeugt, das Variablenname und Variablenwert ausließt.

    Var Wert
    Test Muster
    

    field.h

    #ifndef READ_CONFIG_H
    #define READ_CONFIG_H
    
    #include <fstream>
    #include <iostream>
    #include <string>
    
    class Files
    {
        // VARIABLEN
        std::string vars_[64][2];   // max. 64 lines, 2 states: varname and value
        const char* filename_;
        std::fstream file_;
        int items_;
    
        public:
            // GETTERS
            const char* getVar_(const char* var);
    
            // SETTERS
            void  setVar_(const char* var, const char* value);
    
            // COSTRUCTORS
            Files(const char* filename, bool &proof);
           ~Files();
    
        private:
            // FUNCTIONS
            void write_();
            void add_();
    
    };
    
    #endif
    

    Der Konstruktor sieht hierbei folgendermaßen aus:

    Files::Files(const char* filename, bool &proof)
    {
        // VARIABLES
        filename_   = new char[255];
        filename_   = filename;
        items_      = 0;        // index for loop
    
        char* c     = new char[255];
        bool  b     = 0;        // index (varname or value?)
    
        file_.open(filename_,ios::in);    // open file
    
        if ( file_.good() )
        {
            cout << "Datei geladen: " << filename_ << endl;
    
            while ( ! file_.eof() )
            {
                // Read and Save varname
    
                file_ >> c;
                if ( ! file_.eof() )
                {
                    vars_[items_][b] = c;
    
                    if ( b == 0 )
                    {
                        b = 1;
                    } else {
                        b = 0;
                        items_++;
                    }
    
                    cout << vars_[items_][0] << ":" << vars_[items_][1] << endl;
                }
            }
    
            proof = true;
    
        } else {
            cout << "Could not open " << filename_ << "!" << endl;
            this->~Files();
    
            proof = false;
        }
    
        file_.close();
    }
    

    Lege ich nun ein Objekt an, dann wird mir an der Stelle von

    cout << vars_[items_][0] << ":" << vars_[items_][1] << endl;
    

    folgendes ausgegeben:

    Var:
    :
    test:
    :

    Dennoch wird die Datei richtig geschrieben:

    void Files::write_()
    {
        file_.open(filename_,ios::out);    // open file
    
        for( int i = 0; i <= items_; i++ )
        {
            file_ << vars_[i][0] << " " << vars_[i][1] << endl;
        }
    
        file_.close();
    }
    

    (Die Funktion wird auch im Destruktor aufgerufen)

    Ich weiß nicht mehr weiter und bitte um Hilfe.



  • } else {
                        b = 0;
                        items_++;
                    }
    
                    cout << vars_[items_][0] << ":" << vars_[items_][1] << endl;
    

    items_ ist jetzt schon auf dem nächsten Element.



  • manni66 schrieb:

    items_ ist jetzt schon auf dem nächsten Element.

    Autsch, das tut nur selbst weh. 😡

    Dann liegt das eigentliche Problem vorbeigeschossen und es liegt in der const char* File::getVar_()

    const char* Files::getVar_(const char* var)
    {
        for ( int i; i < items_; i++ )
        {
            if ( var == ( vars_[i][0].c_str() ) )
            {
                return vars_[i][1].c_str();
            }
        }
    
        return "";
    }
    

    Wenn ich diese Funktion nämlich mit

    Files config( CONFIGFILE, test );
    
    // CODE (Überprüfung der bool test
    
    cout << config.getVar_("test") << endl;
    

    aufrufe, erhalte ich eine Leerzeile in der Ausgabe bzw. den String, der zurückgegeben werden soll, wenn keine Übereinstimmung gefunden wird, obwohl vars_[1][0] in diesem Fall "test" betragen müsste.



  • Schon schlimm, was manche als C++ bezeichnen. Hierfür würde ich einen std::ifstream nehmen und die Key-Value Paare in eine std::map<std::string, std::string> speichern. In etwa so (ungetestet):

    class property_reader
    {
        std::map<std::string, std::string> properties;
    
    public:
    
        const std::string filename;
    
        property_reader(std::string filename)
            : filename(filename)
        {
            std::ifstream is(filename.c_str());
    
            std::string line;
            while(std::getline(is, line))
            {
                size_t i = line.find(' ');
                properties.insert(std::make_pair(line.substr(0, i), line.substr(i)));
            }
        }
    
        std::string get(const std::string& property) const
        {
            auto i = properties.find(property);
    
            if(i != properties.end)
                return i->second;
    
            throw not_found_error(property);
        }
    
        void set(std::string key, std::string value)
        {
            map.insert(std::make_pair(std::move(key), std::move(value));
        }
    
        ~property_reader()
        {
            std::ofstream os(filename.c_str());
    
            for(auto i = properties.begin(); i != properties.end(); ++i)
                os << i->first << ' ' << i->second << '\n';
        }
    };
    


  • Daran hatte ich gar nicht gedacht. Ich werde es mal probieren, danke.

    EDIT:

    Was hat es mit den auto-Variablen auf sich?
    Der Compiler gibt mir die Fehlermeldung aus, dass diese nicht ohne Dateityp deklariert werden können.



  • Ki schrieb:

    Was hat es mit den auto-Variablen auf sich?
    Der Compiler gibt mir die Fehlermeldung aus, dass diese nicht ohne Dateityp deklariert werden können.

    In C++03 bezeichnete es IM(H)O "RAII", deshalb brauchst du auch einen Datentyp. Im kommenden Standard bedeutet es die Ableitung des Datentyps durch seinen Initialisierungswert.



  • und welcher Datentyp muss das in diesem Fall sein?
    Wenn ich die Variable mit

    std::map<std::string,std::string>::iterator in;
    

    deklariere, wie heir (http://www.cplusplus.com/reference/stl/map/find/) beschrieben, dann gibt es haufenweise no-match-Fehlermeldungen.



  • Thema erledigt, Problem gelöst. Habe den Code nach einigen Schwierigkeiten folgendermaßen umgeschrieben und es funktioniert wunderbar:

    reader.h

    #ifndef READER_H
    #define READER_H
    
    #include <iostream>
    #include <string>
    #include <map>
    #include <fstream>
    
    class Reader
    {
        // VARIABLES
        std::map<std::string, std::string> items_;
        const std::string filename_; 
    
        public:
            // CONSTRUCTORS
            Reader(std::string filename);
            ~Reader();
    
            // GETTERS
            std::string get(const std::string& property) const;
    
            // SETTERS
            void set(std::string key, std::string value);
    
            // FUNCTIONS
            void write();
    
    };
    
    #endif
    

    reader.cpp

    #include "reader.h"
    
    Reader::Reader(std::string filename)
        : filename_(filename)
    {
        std::ifstream is(filename_.c_str());
    
        std::string line;
    
        while(std::getline(is, line))
        {
            size_t i = line.find(' ');
    
            items_.insert(std::make_pair(line.substr(0, i), line.substr(i).erase(0,1)));
        }
    }
    
    std::string Reader::get(const std::string& item) const
    {
        std::map<std::string, std::string>::const_iterator in = items_.find(item);
    
        if(in != items_.end())
        {
            return in->second;
        }
    
        return "";
    }
    
    void Reader::set(std::string key, std::string value)
    {
        items_.insert(std::make_pair( key , value ) );
    }
    
    void Reader::write()
    {
        std::ofstream os(filename_.c_str());
    
        for( std::map<std::string, std::string>::iterator in = items_.begin(); in != items_.end(); ++in )
        {
            os << in->first << ' ' << in->second << '\n';
        }
    }
    
    Reader::~Reader()
    {
        write();
    }
    

    EDIT:
    Entschuldigung für den Doppelpost, ich dachte, man könne Beiträge löschen.


Anmelden zum Antworten