Textdatei einlesen und trennen...



  • Hi ihr programmierer,
    bin ganz neu auf dem gebiet c++ und hab vorher nur mit anderen sprachen zu tu gehabt. dank der uni komme ich jetzt auch auf den geschmack etwas mit c++ machen zu dürfen/müssen.

    b2t: ich möchte eine textdatei einlesen (klappt auch super) nur leider ist sie wie folgt aufgebaut:

    2 ; Münchner Straße
    4 ; Bahnhofsstraße
    16; Martin-Luther-Platz

    dort möchte ich jetzt die zahlen und die namen einzelnd haben, d.h. ich möchte ne vorschleife laufen lassen und dort dann einen knoten mit diesen beiden angaben erstellen ( knoten(index,name) ). dazu muss ich aber iwie die beiden dinge trennen können.

    hier mein bisheriger code:

    #include <stdafx.h>
    #include <cstdlib>
    #include <iostream>
    #include <fstream>
    #include <string>
    
    using namespace std;
    
    ifstream inFile;
    /*ifstream inFileOut;*/
    ofstream outFile;
    
    /*takes filename from stdin and trys to open file*/
    void openFile();
    /*writes output file from inFile*/
    void writeToFile();
    
    int main(){
        openFile();
        writeToFile();
    	getchar();
        return 0;
    }
    
    void openFile(){
    
        inFile.open("knoten.txt");
        if(inFile.fail()){
            char c;
            cerr << "Fehler: Datei konnte nicht geöffnet werden\n" << endl;
            cin >> c;
            //exit(1);
        }
    }
    
    void writeToFile(){
        cout << "Ich schreibe die TextDatei..." << endl;
    	char c;
        outFile.open("outputKnoten.txt");
        while(inFile.get(c)){
            if(c != ' '){
    			outFile.put(c);
            }
        }
        outFile.close();
        cout << "Datei erfolgreich erstellt." << endl;
    }
    

    wäre super, wenn mir jemand einen tip geben könnte, wie das funktionieren könnte und bitte daran denken das ich von c++ nicht wirklich ahnung habe...

    vielen dank! 🙂

    grüße palme



  • Naja du könntest erstmal versuchen die Datei überhaupt einzulesen,was du ja bis jetzt überhaupt nicht machst :D.
    Am besten du liest sie in einen std::string ein.Und danach behandelst du den std::string nach deinen suchkriterien.

    Hier eine Referenz:
    std::string

    zum einlesen einer ganzen zeile würde ich so vorgehen

    std::ifstream datei("deinedatei.txt");
    std::vector<std::string> inhalt;
    std::string temp;
    
    while(getline(datei,temp))
    {
       inhalt.push_back(temp);
    }
    

    Zu std::vector hier mehr

    Danach kannst du dann auf die Inhalte jeweils die string-suchfunktionen und ersetzfunktionen anwenden.
    und dann wieder in einen std::vector, oder sogar in eine std::map speichern.



  • danke für die schnelle antwort...
    ich habe jetzt folgendes geschrieben:

    string c;
    	vector<string> inhalt;
    
        while(getline(inFile,c)){
            if(c != ""){
    			inhalt.push_back(c);
            }
        }
    
        for (int i=0; i < inhalt.size(); i++)
    		cout << " " << inhalt[i] << endl;
    	cout << endl;
    

    das gibt mir alles aus was in dem vector steht, d.h. alles was ich vorher in der textdatei hatte, steht jetzt auch in der konsole.

    ich weiß aber nicht wie ich es schaffe die zahlen und die strings dahinter zu trennen... also ich möchte ja knoten erstellen und dazu brauche in ein int und einen string für den namen.

    danke für eure hilfe, auch wenn ihr sicherlich von solchen noob-fragen genervt seid.

    //edit ok ich hab hinbekommen... trotzdem vielen dank für eure hilfe, ohne wäre ich nicht drauf gekommen!



  • jetzt hab ich ein aderes problem 🙂

    und zwar konnte ich den vorherigen string wunderbar beim semikolon teilen, allerdings hab ich jetzt für die pfeile zwei semikolon. beispiel für einen pfeil: 2 ; 16 ; 7

    ich würde gerne an alle drei zahlen rankommen... kann mir da jemand weiterhelfen?? mit find(";"); bekomme ich ja nur das erste semikolon...

    wenn ich das mit find versuche bekomme ich zweimal die gleiche ausgabe:

    int pos = c.find(";");
    int pos2 = c.find_last_of(";");
    cout << pos << pos2 << endl;
    

    ich bekomme zwei mal die zwei ausgespuckt...



  • while(c.find(";") != std::string::npos)
    {
       //hier deine ersetzungsroutine rein
    }
    

    Keine Garantie, habs nur grad ausem Kopf hingeschrieben.



  • jup damit könnte ich das zweite semikolon erwischen, dankeschön... probiere das heute abend aus und werde wieder schreiben 😛



  • so was ich bisher habe:
    ich kann aus zwei verschiedenen text-dateien knoten und pfeile einlesen. diese kann ich dann auch erstellen.

    jetzt soll ich eine Adjazenzliste mit diesen erstellen. Wie löse ich das am besten? mit einem vector in dem einträge einer linked-list sind? wenn ja wie fang ich da am besten an??
    wie gesagt bin der totale anfänger, aber gern zum lernen bereit...

    hier ein ausschnitt aus dem code nochmal:

    void writeToFile(){
    	//creation of the knoten--------------------------------
    	string c;
        while(getline(inFileKnoten,c)){
    		//remove spaces
    		trimString(c);
    
    		//the semikolon as an indicator
    		int pos = c.find(";");
    
    		//find the word in the stringline
    		string name = c.substr(pos+1);
    
    		//find the number in the stringline
    		int number = atoi(c.substr(0,pos).c_str());
    
    		//create the knoten
    		knoten myFirstKnoten = knoten(number,name);
    		cout << myFirstKnoten.print() << endl;
        }
    	//END creation of the knoten--------------------------------
    
    	//creation of the pfeil--------------------------------
    	string s;
    
    	//vector<string> inhaltPfeil;
    
        while(getline(inFilePfeil,s)){
    		trimString(s);
    
    		//the semikolon as an indicator
    		int pos = s.find(";");
    		int pos2 = s.find_last_of(";");
    
    		//fin alhpa and omega and weight
    		int alpha = atoi(s.substr(0,pos).c_str());
    		int omega = atoi(s.substr(pos + 1, pos2).c_str());
    		int gewicht = atoi(s.substr(pos2 + 1, s.length()).c_str());
    
    		pfeil myPfeil = pfeil(alpha, omega, gewicht);
    		cout << alpha << " " << omega << " " << gewicht << endl;
    	}
    
    	//END creation of the knoten--------------------------------
    }
    

    jetzt würde ich gerne die pfeile und die knoten in eine containerklasse packen wollen, damit ich die dort speichern kann und wieder darauf zugreifen kann...

    nochmals vielen dank für eure (deine 😉 ) hilfe...



  • Also vielleicht wäre es noch interessant wenn du uns die Defintionen deiner Typen "pfeil" und "knoten" mitlieferst. 😉
    Weiterhin ist das atio() nicht gerade die Variante wie man es in C++ macht, schau dazu mal im FAQ da gibt es einen Thread "Einmal Zahl nach String und zurück"(oder so ähnlich) da wird beschrieben wir du besser castest.



  • ich bin gerade auf der arbeit deshalb kann ich die definitionen jetzt nicht mit anpinnen sry, aber die bestehen eh nur aus jeweils einem constructor für jede klasse.

    für den pfeil nimmt der constructor alpha, omega und das gewicht (also anfang, ende und die strcke sozusagen) und beim knoten einfach nur die nr. und den namen.
    die klassen und die jewiligen header-dateien heißen knoten und pfeil.

    das mit dem casten werde ich dann heute noch verändern, wenn es nicht so schön ist... danke für den tip. hier in der FAQ steht tatsächlich solch ein beitrag: http://www.c-plusplus.net/forum/viewtopic-var-t-is-39488.html, schön dieser service 😉



  • Vielleicht wäre für dich auch noch interessant zu wissen, das der Container std::map. dir das speichern von Schlüssel-Wertpaaren erleichtert.Dann kannst du da auch eventuell deinen Knoten mit seiner ID abspeicher.



  • ich komme nicht weiter 😞
    ich kann jetzt meine knoten und kanten erstellen, allerdings weiß ich nicht wie ich diese jetzt sinnvoll in einen container (map???, vektor + linklist???) speichern soll...

    hier mal was ich bisher habe:

    // importExport.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
    //
    
    #include <stdafx.h>
    #include <cstdlib>
    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <map>
    #include <string>
    #include "knoten.h"
    #include "pfeil.h"
    
    using namespace std;
    
    ifstream inFileKnoten;
    ifstream inFilePfeil;
    /*ofstream inFileOut;*/
    ofstream outFile;
    
    /*takes filename from stdin and trys to open file*/
    void openFile();
    /*writes output file*/
    void writeToFile();
    void stringToInt(string &);
    void trimString(string &);
    
    int main(){
        openFile();
        writeToFile();
    	getchar();
        return 0;
    }
    
    void openFile(){
    
        inFileKnoten.open("knoten.txt");
        if(inFileKnoten.fail()){
            char c;
            cerr << "Fehler: Datei knoten.txt konnte nicht geöffnet werden\n" << endl;
            cin >> c;
        }
    
    	inFilePfeil.open("pfeile.txt");
    	if(inFilePfeil.fail()){
            char c;
            cerr << "Fehler: Datei pfeile.txt konnte nicht geöffnet werden\n" << endl;
            cin >> c;
        }
    }
    
    void writeToFile(){
        //cout << "Ich schreibe die TextDatei..." << endl;
    
    	//creation of the knoten--------------------------------
    	string c;
    
        while(getline(inFileKnoten,c)){
    		//remove spaces
    		trimString(c);
    
    		//the semikolon as an indicator
    		int pos = c.find(";");
    
    		//find the word in the stringline
    		string name = c.substr(pos+1);
    
    		//find the number in the stringline
    //to-DO change the cast!!!
    		int number = atoi(c.substr(0,pos).c_str());
    
    		//create the knoten
    		knoten myFirstKnoten = knoten(number,name);
    
    		cout << "my knoten: " << myFirstKnoten.print() << endl;
        }
    	//END creation of the knoten--------------------------------
    
    	//creation of the pfeil--------------------------------
    	string s;
    
        while(getline(inFilePfeil,s)){
    		trimString(s);
    
    		//the semikolon as an indicator
    		int pos = s.find(";");
    		int pos2 = s.find_last_of(";");
    
    		//find alhpa and omega and weight
    //to-DO change the cast!!!
    		int alpha = atoi(s.substr(0,pos).c_str());
    		int omega = atoi(s.substr(pos + 1, pos2).c_str());
    		int gewicht = atoi(s.substr(pos2 + 1, s.length()).c_str());
    
    		pfeil myPfeil = pfeil(alpha, omega, gewicht);
    		cout << "my kanten: " << alpha << " " << omega << " " << gewicht << endl;
    	}
    
    	//END creation of the knoten--------------------------------
    }
    
    //removes the spaces out of the string
    void trimString(string &str) {
    	for (int i=0; i < str.length(); i++)
    		if (str[i] == ' ') {
    			str.erase(i,1);
    			i--;
    		}
    }
    

    und hier die pfeil(kanten) und die knoten klassen, die jeweils einen header dazu haben

    #include "stdafx.h"
    #include "pfeil.h"
    #include <cstdio>
    
    using namespace std;
    
    int alpha;
    int omega;
    int gewicht;
    
    pfeil::pfeil()
    :alpha(0), omega(0), gewicht(0)
    {
    }
    
    pfeil::pfeil(int alp, int om, int gew)
    :alpha(alp), omega(om), gewicht(gew)
    {
    }
    
    #include "stdafx.h"
    #include "knoten.h"
    #include <cstdio>
    #include <string>
    #include <sstream>
    
    using namespace std;
    
    knoten::knoten()
    :index(0), name("0")
    {
    }
    
    knoten::knoten(int ind, string nam)
    :index(ind), name(nam)
    {
    }
    
    string knoten::print()
    {
    	ostringstream temp;
        temp << index;
        string zahlenString = temp.str();
    
    	return zahlenString + "; " + name;
    }
    

    bitte um hilfe... weiß wirklich nicht wie es weitergeht



  • Hallo Palme,

    falls Du Informationen aus einer Datei liest, so solltest Du immer die Funktionen des std::istream dafür nutzen. Ein Lesen mit getline und anschließendem Auseinanderfiseln des strings ist keine Lösung. Man versieht dafür jede Klasse/Struktur, die ausgeben und/oder eingelesen wird, mit einem Streamingoperator. Also in Deinem Fall:

    #include <string>
    #include <iosfwd>
    // --   Knoten-Klasse
    class knoten
    {
    public:
        knoten();
        knoten(int ind, const std::string& nam);
    
        friend std::istream& operator>>( std::istream& in, knoten& k );
        friend std::ostream& operator<<( std::ostream& out, const knoten& k ); // ersetzt 'print'
    private:
        int index;
        std::string name;
    };
    // --   Pfeil-Klasse
    class pfeil
    {
    public:
        pfeil();
        pfeil(int alp, int om, int gew);
    
        // --   Pfeil einlesen & ausgeben
        friend std::istream& operator>>( std::istream& in, pfeil& p );
        friend std::ostream& operator<<( std::ostream& out, pfeil& p );
    
    private:
        int alpha;
        int omega;
        int gewicht;
    };
    

    Die Implementierung sähe dann so aus:

    // --   Helferlein zum Überlesen einzelner Zeichen
    template< char C >
    std::istream& Char( std::istream& in )
    {
        char c;
        if( in >> c && c != C )
            in.setstate( std::ios_base::failbit );
        return in;
    }
    
    // --   Knoten-Klasse
    knoten::knoten()
        : index(0), name("0")
    {}
    
    knoten::knoten(int ind, const std::string& nam)
        : index(ind), name(nam)
    {}
    
    // --   Ausgabe (ersetzt: string knoten::print() )
    std::ostream& operator<<( std::ostream& out, const knoten& k )
    {
        return out << k.index << "; " << k.name;
    }
    // --   Einlesen eines Knotens
    std::istream& operator>>( std::istream& in, knoten& k )
    {
        return getline( in >> k.index >> Char<';'> >> std::ws, k.name );
    }
    
    // --  Pfeil
    pfeil::pfeil()
        : alpha(0), omega(0), gewicht(0)
    {}
    
    pfeil::pfeil(int alp, int om, int gew)
        : alpha(alp), omega(om), gewicht(gew)
    {} 
    
    std::istream& operator>>( std::istream& in, pfeil& p )
    {
        return in >> p.alpha >> Char<';'> >> p.omega >> Char<';'> >> p.gewicht;
    }
    std::ostream& operator<<( std::ostream& out, pfeil& p )
    {
        return out << p.alpha << " " << p.omega << " " << p.gewicht;
    }
    

    Da ich gerade an einem Projekt sitze, das nur deshalb dreimal so viel Aufwand erfordert wie es eigentlich erfordern sollte und das alles nur weil der Programmierer globale Variablen verwendet ...

    hier noch mal der ernst gemeinte Hinweis: vermeide globale Variablen!

    palmdale schrieb:

    .. bin ganz neu auf dem gebiet c++ und hab vorher nur mit anderen sprachen zu tu gehabt.

    .. dann solltest Du das auch wissen; das gilt für alle Programmiersprachen.

    Das Öffen der Dateien kannst Du ruhig in das main nehmen, dann sieht es so aus:

    #include <fstream>
    #include <iostream>
    
    void readFromFile( std::istream& fileKnoten, std::istream& filePfeil );
    using namespace std;
    
    int main()
    {
        ifstream inFileKnoten( "knoten.txt" );
        if( !inFileKnoten.is_open() )
        {
            char c;
            cerr << "Fehler: Datei knoten.txt konnte nicht geöffnet werden\n" << endl;
            cin >> c;
            return -1;
        }
    
        ifstream inFilePfeil( "pfeile.txt" );
        if( !inFilePfeil.is_open() )
        {
            char c;
            cerr << "Fehler: Datei pfeile.txt konnte nicht geöffnet werden\n" << endl;
            cin >> c;
            return -1;
        }
    
        readFromFile( inFileKnoten, inFilePfeil ); // Lesen aus den Dateien
    
        getchar();
        return 0;
    }
    

    und dank der Vorarbeit wird jetzt das Lesen ganz einfach:

    void readFromFile( std::istream& fileKnoten, std::istream& filePfeil )
    {
        for( knoten k; fileKnoten >> k; )
        {
            cout << "my knoten: " << k << endl;
        }
        for( pfeil p; filePfeil >> p; )
        {
            cout << "my kanten: " << p << endl;
        }
    }
    

    palmdale schrieb:

    ich komme nicht weiter 😞
    ich kann jetzt meine knoten und kanten erstellen, allerdings weiß ich nicht wie ich diese jetzt sinnvoll in einen container (map???, vektor + linklist???) speichern soll...

    Das kann man erst dann entscheiden, wenn bekannt ist, was Du mit den Knoten und Kanten vor hast. Erst müssen die Anforderungen klar sein, dann kann man sagen, wie das Programm aussehen soll.

    Was ist der Zweck Deines Programms? was soll es tun? was ist der Output?

    Gruß
    Werner



  • wow danke für deine ausführliche antwort, werde mir das zu herzen nehmen und meinen code nochmal überarbeiten. jetzt zu dem graphen.

    im allgemeinen möchte ich erstmal einen container der kanten und knoten speichert. dieser soll dann folgendes ausgeben:

    • Ermittlung des Ausgangsgrades g+(u) und Eingangsgrades g+(u) eines wählbaren
    Knotens
    • Ermittlung der Nachbarn (Vorgänger und Nachfolger) eines wählbaren Knotens

    echt nochmal vielen dank für die tipps... ich such mich bald wund im internet um was gescheites zu finden. werde jetzt mein code nochmal überarbeiten.

    //edit: wenn ich deinen code benutze gibt es einen fehler das der knoten nicht erkannt wird, wenn du den erstellen willst...
    error C2065: 'knoten': nichtdeklarierter Bezeichner (in der readFromFile methode)
    wie verbinde ich denn diese beiden klassen, damit der erkannt wird?

    diese sprache macht mir keinen spaß :(, aber wenigstens gibt es leute die helfen



  • palmdale schrieb:

    • Ermittlung des Ausgangsgrades g+(u) und Eingangsgrades g+(u) eines wählbaren
    Knotens
    • Ermittlung der Nachbarn (Vorgänger und Nachfolger) eines wählbaren Knotens

    Oh - ja dann ist kein Container aus dem C++ Standard wirklich geeignet - schau Dir mal die boost.graph-Librarie an. Die Alternative bestände darin, Dir selbst etwas aus den C++-Containern zusammenzubauen.

    Jeder Knoten enthält dann schon einen Container (vector oder list) mit Zeigern auf seine Nachbarn und dem dazugehörigen Gewicht. Die Knoten selbst könnte man dann in eine std::map abladen, aber wieder nur als Pointer (besser boost.shared_ptr) da sie nicht kopierbar sein dürfen, damit ihre Vorgänger sie sicher wiederfinden.

    palmdale schrieb:

    ich such mich bald wund im internet um was gescheites zu finden. werde jetzt mein code nochmal überarbeiten.

    .. es gibt furchtbar wenig zum Thema IO in C++ - warum auch immer.

    Gruß
    Werner



  • die aufgabe besteht leider darin das ich diese boost.graph-Librarie nicht nehmen kann... 😞

    //edit: hab jetzt deins zum laufen gebracht und beginne zu verstehen was du da machst aufgrund meiner kenntnisse in anderen sprachen.



  • palmdale schrieb:

    //edit: wenn ich deinen code benutze gibt es einen fehler das der knoten nicht erkannt wird, wenn du den erstellen willst...
    error C2065: 'knoten': nichtdeklarierter Bezeichner (in der readFromFile methode)
    wie verbinde ich denn diese beiden klassen, damit der erkannt wird?

    Dann hast Du das #include "knoten.h" dort vergessen.

    palmdale schrieb:

    diese sprache macht mir keinen spaß :(, aber wenigstens gibt es leute die helfen

    .. der Spaß kommt mit der Zeit 😉

    Gruß
    Werner



  • .. der Spaß kommt mit der Zeit 😉

    darauf warte ich jetzt aber schon ne ganze weile, in den anderen (neueren) sprachen hab ich mich sehr schnell zurecht gefunden, aber dieses c++ ist für mich n bisschen wie ein krampf.

    hab deine sachen jetzt zum laufen gebracht und beginne zu verstehen, wie du das aufgebaut hast. vielen vielen dank nochmal dafür (ich hoffe ich halte dich nicht von deinem derzeitigen projekt ab).

    hast du ne idee wie man das löst? ich hatte zuerst an einen vektor gedacht, der eine link liste in sich trägt, eine map zu implementieren hab ich versucht, allerdings bisher ohne erfolg, da ich das mit dem pair nicht verstanden habe...



  • palmdale schrieb:

    .. der Spaß kommt mit der Zeit 😉

    darauf warte ich jetzt aber schon ne ganze weile, in den anderen (neueren) sprachen hab ich mich sehr schnell zurecht gefunden, aber dieses c++ ist für mich n bisschen wie ein krampf.

    Hallo Palme,
    C++ ist eine schwierige Sprache, und sie ist anders.

    palmdale schrieb:

    hab deine sachen jetzt zum laufen gebracht und beginne zu verstehen, wie du das aufgebaut hast. vielen vielen dank nochmal dafür (ich hoffe ich halte dich nicht von deinem derzeitigen projekt ab).

    .. gucke gerade Song Contest - da bin ich geistig nicht ausgelastet. 🕶

    palmdale schrieb:

    hast du ne idee wie man das löst? ich hatte zuerst an einen vektor gedacht, der eine link liste in sich trägt, eine map zu implementieren hab ich versucht, allerdings bisher ohne erfolg, da ich das mit dem pair nicht verstanden habe...

    Ein pair ist einfach eine Struktur mit zwei Membern (first und second) nicht mehr und nicht weniger. Bei einer std::map wird der Member first als Schlüssel benutzt, um das Element (also das ganze pair) zu identifizieren. In second kann dann stehen was will.

    Um den Graph zu realisieren würde ich Dir im Prinzip folgendes vorschlagen. Rüste zunächst Deine knoten-Klasse auf, die wird später Teil des Graphs.

    // --   Knoten-Klasse
    class knoten
    {
    public:
        typedef knoten* KnotenPtr; // evt. typedef boost::shared_ptr< knoten > KnotenPtr;
        struct Next
        {   
            Next( KnotenPtr nachfolger, int gewicht )
                : m_nachfolger( nachfolger ), m_gewicht( gewicht )
            {}
            KnotenPtr m_nachfolger;
            int m_gewicht;
        };
        void Nachfolger( KnotenPtr next, int gewicht );
        int Index() const { return index; }
    // -- usw. wie vorher
    private:
        std::vector< Next > m_nachfolger; // erfordert #include <vector>
    

    Damit bekommt jeder Knoten einen Container in dem alle Nachfolger mit den Gewichten der Kanten stehen.

    In der Methode readFromFile

    typedef std::map< int, knoten::KnotenPtr > Graph;   // erfordert #include <map>
    Graph readFromFile( std::istream& fileKnoten, std::istream& filePfeil );
    

    - Achtung - neuer Returntyp - muss der Graph zusammen gebaut werden:

    Graph readFromFile( std::istream& fileKnoten, std::istream& filePfeil )
    {
        Graph graph;
        // --  erst alle Knoten einlesen, die Liste aller Anchfolger ist jeweils noch leer
        for( knoten k; fileKnoten >> k; )
        {
            graph[ k.Index() ] = new knoten( k );
            cout << "neuer knoten: " << k << endl;
        }
    
        // --  dann die Kanten einlesen und die Knoten verbinden
        for( pfeil p; filePfeil >> p; )
        {
            // erst den Ausgangsknoten suchen
            Graph::iterator alpha = graph.find( p.alpha );
            if( alpha == graph.end() )
            {
                cerr << "Ausgangsknoten-Knoten " << p.alpha << " nicht vorhanden " << endl;
                break;
            }
            // .. dann den Eingangsknoten suchen
            Graph::iterator omega = graph.find( p.omega );
            if( omega == graph.end() )
            {
                cerr << "Eingangs-Knoten " << p.omega << " nicht vorhanden " << endl;
                break;
            }
            alpha->second->Nachfolger( omega->second, p.gewicht );
        }
        return graph;
    }
    

    Achtung -ich habe die Member von 'pfeil' public gemacht, da diese Klasse nur zum Einlesen genutzt wird und es so einfacher wird.

    Bevor ich lange erkläre - frag' einfach was Du nicht verstehst.

    Gruß
    Werner



  • tausend dank ich medietiere darüber und werde jetzt schlafen gehen. morgen werd ich bestimmt dann fragen stellen 😉 wirklich danke für deine zeit.



  • so jetzt ist alles eingebunde, ich bekomme aber leider eine fehlermeldung mit der ich wenig anfangen kann...

    Verweis auf nicht aufgelöstes externes Symbol ""public: void __thiscall knoten::Nachfolger(class knoten *,int)" (?Nachfolger@knoten@@QAEXPAV1@H@Z)" in Funktion ""class std::map<int,class knoten *,struct std::less<int>,class std::allocator<struct std::pair<int const ,class knoten *> > > __cdecl readFromFile(class std::basic_istream<char,struct std::char_traits<char> > &,class std::basic_istream<char,struct std::char_traits<char> > &)" (?readFromFile@@YA?AV?map@HPAVknoten@@U?map@HPAVknoten@@U?less@H@std@@V?allocator@U?allocator@U?pair@$$CBHPAVknoten@@@std@@@3@@std@@AAV?basic_istream@DU?basic\_istream@DU?char_traits@D@std@@@2@0@Z)"

    ich verstehe auch nicht wo du die neuen methoden wie nachfolger in der knten class implementierst. bisher haste die ja nur in den header geschrieben, richtig?

    hier mal meine header und meine knoten klasse (hab den header in eine extra knoten.h geschrieben):

    knoten.h

    #include "stdafx.h"
    #include <string>
    #include <iosfwd>
    #include <vector>
    
    using namespace std;
    
    // --   Knoten-Klasse
    class knoten
    {
    public:
        knoten();
        knoten(int ind, const string& nam);
    
    	typedef knoten* KnotenPtr;
        struct Next
        {  
            Next( KnotenPtr nachfolger, int gewicht )
                : m_nachfolger( nachfolger ), m_gewicht( gewicht )
            {}
            KnotenPtr m_nachfolger;
            int m_gewicht;
        };
    
        void Nachfolger( KnotenPtr next, int gewicht );
        int Index() const { return index; } 
    
        friend istream& operator>>( istream& in, knoten& k );
        friend ostream& operator<<( ostream& out, const knoten& k );
    private:
        int index;
        string name;
    	std::vector< Next > m_nachfolger;
    };
    

    knoten.cpp

    #include "stdafx.h"
    #include <string>
    #include <iosfwd>
    #include "knoten.h"
    
    using namespace std;
    
    // --   Helferlein zum Überlesen einzelner Zeichen
    template< char C >
    istream& Char( istream& in )
    {
        char c;
        if( in >> c && c != C )
            in.setstate( ios_base::failbit );
        return in;
    }
    
    // --   Knoten-Klasse
    knoten::knoten()
        : index(0), name("0")
    {}
    
    knoten::knoten(int ind, const string& nam)
        : index(ind), name(nam)
    {}
    
    // --   Ausgabe eines Knotens
    ostream& operator<<( ostream& out, const knoten& k )
    {
        return out << k.index << "; " << k.name;
    }
    // --   Einlesen eines Knotens
    istream& operator>>( istream& in, knoten& k )
    {
        return getline( in >> k.index >> Char<';'> >> ws, k.name );
    }
    

    und hier noch der vollständigkeit wegen die main

    // alg_graph.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
    //
    
    #include "stdafx.h"
    #include <fstream>
    #include <iostream>
    #include "knoten.h"
    #include "pfeil.h"
    #include <map>
    
    using namespace std;
    
    typedef std::map< int, knoten::KnotenPtr > Graph;
    Graph readFromFile( std::istream& fileKnoten, std::istream& filePfeil ); 
    
    int main()
    {
        ifstream inFileKnoten( "knoten.txt" );
        if( !inFileKnoten.is_open() )
        {
            char c;
            cerr << "Fehler: Datei knoten.txt konnte nicht geöffnet werden\n" << endl;
            cin >> c;
            return -1;
        }
    
        ifstream inFilePfeil( "pfeile.txt" );
        if( !inFilePfeil.is_open() )
        {
            char c;
            cerr << "Fehler: Datei pfeile.txt konnte nicht geöffnet werden\n" << endl;
            cin >> c;
            return -1;
        }
    
        readFromFile( inFileKnoten, inFilePfeil ); // Lesen aus den Dateien
    
        getchar();
        return 0;
    }
    
    Graph readFromFile( std::istream& fileKnoten, std::istream& filePfeil )
    {
        Graph graph;
        // --  erst alle Knoten einlesen, die Liste aller Anchfolger ist jeweils noch leer
        for( knoten k; fileKnoten >> k; )
        {
            graph[ k.Index() ] = new knoten( k );
            cout << "neuer knoten: " << k << endl;
        }
    
        // --  dann die Kanten einlesen und die Knoten verbinden
        for( pfeil p; filePfeil >> p; )
        {
            // erst den Ausgangsknoten suchen
            Graph::iterator alpha = graph.find( p.alpha );
            if( alpha == graph.end() )
            {
                cerr << "Ausgangsknoten-Knoten " << p.alpha << " nicht vorhanden " << endl;
                break;
            }
            // .. dann den Eingangsknoten suchen
            Graph::iterator omega = graph.find( p.omega );
            if( omega == graph.end() )
            {
                cerr << "Eingangs-Knoten " << p.omega << " nicht vorhanden " << endl;
                break;
            }
            alpha->second->Nachfolger( omega->second, p.gewicht );
        }
        return graph;
    }
    


  • du hast nur vergessen die fkt zu definieren:
    void Nachfolger( KnotenPtr next, int gewicht );

    Und deshalb geht das kompilieren auch fehlerfrei und erst beim Linken am Ende sagt dir der Linker die Fehlermeldung:

    Verweis auf nicht aufgelöstes externes Symbol ""public: void __thiscall knoten::Nachfolger(class knoten *,int)" (?Nachfolger@knoten@@QAEXPAV1@H@Z)" in Funktion ""class std::map<int,class knoten *,struct std::less<int>,class std::allocator<struct std::pair<int const ,class knoten *> > > __cdecl readFromFile(class std::basic_istream<char,struct std::char_traits<char> > &,class std::basic_istream<char,struct std::char_traits<char> > &)" (?readFromFile@@YA?AV?map@HPAVknoten@@U?map@HPAVknoten@@U?less@H@std@@V?allocator@U?allocator@U?pair@$$CBHPAVknoten@@@std@@@3@@std@@AAV?basic_istream@DU?basic\_istream@DU?char_traits@D@std@@@2@0@Z)"

    Das nicht mehr fette ist nicht mehr ganz so interessant... Da sagt er dir z.Bsp. in welcher Fkt die nicht definierte aufgerufen werden soll - das sieht hier nur bissl extrem unübersichtlich aus, weil er alle typen vollständig hinschreibt...

    bb


Anmelden zum Antworten