Klassen mit strings



  • Könnte es sein, dass du ein Array aus Strings haben willst (deshalb die string-Zeiger)? Wenn ja, musst du erst mal Speicher für die Strings reservieren und außerdem über den Operator -> auf die Methoden zugreifen (nicht mit . ). Aber fallst du wirklich ein Array aus Strings haben willst, benutze std::vectorstd::string bzw. vector<string>!



  • Twister schrieb:

    Und die Zeiger werden im konstruktor inizialisiert.

    Kannst du mal auflisten, wie?



  • hm... genau das wird es sein. Sie sollen auf einen Array zeigen.

    Konstruktor sieht so aus:

    {
    	anzahl = 1;
    	ifstream in("vok.txt"); //textdatei wo die vokabeln gespeichert werden
    	while(!in.eof())
    	{
    		char ch;
    		in>>ch;
    		if(ch == '\n') ++anzahl; //zählt die Returns in der Datei und
    	}                              //schließt daraus die Anzahl der Vokabeln
    	engl = new string[anzahl]; //hier liegt dann wohl der fehler
    	deu = new string[anzahl];  //und hier auch :D
    	in.close();
    	load();  //die Funktion läd die Vokabeln in den Speicher
    };
    


  • der constriktor sieht gut aus. Zeig mal wie du auf die strings zugreifst und was er dann für fehler gibt



  • Ich poste hier mal die ganzen Funktionen.
    Achja, hab jetzt das schon folgendermaßen umgeändert, daß ich eine struct eingebaut hab um die String Arrays zu vermeiden:

    struct vokabel
    {
       string engl;
       string deu;
    }
    

    Der Konstructor erstellt dann halt einen Array von vokabel

    void load():

    bool englisch = true;   //legt fest ob das Wort Englisch oder Deutsch ist
    int nr = 0;
    ifstream in("vok.txt");
    while(!in.eof())
    {
    	char ch;
    	in>>ch;
    	switch (ch)
    	{
    	case '\n':   //wenn ein Return kommt...
    		englisch = true;   //nächstes Wort Englisch
    		++nr;  //nächste Zeile
    		break;
    	case ' ':  //wenn ein Leer kommt
    		englisch = false;  //nächstes Wort deutsch
    		break;
    	default:     //alle anderen Zeichen und Buchstaben
    		if(englisch)
    		{
    			vok[nr].engl += ch;  //wenn sie englisch sind hier rein schreiben
    		}
    		else
    		{
    			vok[nr].deu += ch;  //wenn sie deutsch sind hier rein
    		}
    	}
    }
    in.close();
    
    void trainer::safe()
    {
    	ofstream out("vok.txt");
    	for(int i=0;i <= anzahl;++i)
    	{
    		out << vok[i].engl << " " << vok[i].deu << endl;
    	};
    	out.close();
    };
    
    void trainer::add(string e, string d)
    {
    	vokabel *tmp = vok;
    	++anzahl;
    	vok = new vokabel[anzahl];
    	for(int i=0;i<anzahl;++i)
    	{
    		vok[i] = tmp[i];  //übernimmt die Werte aus dem Zwischenspeicher
    	}
    	vok[anzahl].deu = d;  //schreibt in den letzten Wert die neue Vokabel
    	vok[anzahl].engl = e;
    	delete [] tmp;
    }
    
    void trainer::abfrage()
    {
    	string answer;
    	srand( (unsigned)time( NULL ) );
    	int zufall = rand()%(anzahl+1);  //zufällige Vokabel-Nr
    	int speak = rand()%1;   //zufällig für Englisch / Deutsch
    	if(speak ==1) cout << vok[zufall].deu;   //gibt nach den Zufallszahlen...
    	else cout << vok[zufall].engl;   //entweder deu oder engl eine Vokabel aus
    	cin >> answer;
          //hier prüft er noch, ob die Antwort mit der gespeicherten übereinstimmt
    	if((speak == 1 && answer == vok[zufall].engl) || (speak == 0 && answer == vok[zufall].deu))
    	{
    		cout << "richtig\n" << endl;
    	}
    	else cout << "falsch " << vok[zufall].engl << " " << vok[zufall].deu << "\n" << endl;
    };
    

    so... evtl poste ich gleich noch die main.

    /edit:

    Achja, er stürzt mir ab, wenn ich:
    -nur auf Vokabelabfrage geh (noch vor der Ausgabe der Zufallsvokabel)
    -wenn ich Vokabeln hinzufügen will (nach der Eingabe der Vokabel, also dann wenn void add() starten sollte)



  • Hi.
    Ich kann nirgends finden wo anzahl initialisiert wird.
    K.



  • war unter "paar Variablen" dabei

    Twister schrieb:

    Hi,

    #include<string>
    using namespace std;
    
    class voktrainer
    {
    private:
       //paar Variablen   <-- int anzahl;
       string *engl;
       string *deu;
    public:
      //die funktionen
    }
    


  • aha doch

    {
        anzahl = 1;
        ifstream in("vok.txt"); //textdatei wo die vokabeln gespeichert werden
        while(!in.eof())
        {
            char ch;
            in>>ch;
            if(ch == '\n') ++anzahl; //zählt die Returns in der Datei und
        }                              //schließt daraus die Anzahl der Vokabeln
        engl = new string[anzahl]; //hier liegt dann wohl der fehler
        deu = new string[anzahl];  //und hier auch :D
        in.close();
        load();  //die Funktion läd die Vokabeln in den Speicher
    };
    

    es muss aber heissen

    anzahl = 0;
    

    und vor load() musst du anzahl wieder auf 0 setzen;
    und in abfrage()

    int zufall = rand()%(anzahl+1);  //zufällige Vokabel-Nr
    

    sollte sein

    int zufall = rand()%(anzahl);  //zufällige Vokabel-Nr
    

    was mir noch auffält ist das du im construktor die variablen deu und engl anlegst. in den funktionen add, safe, load und abfrage aber auf vok zugreifst.
    dann ist da noch

    void trainer::add(string e, string d)
    {
        vokabel *tmp = vok;
        ++anzahl;
        vok = new vokabel[anzahl];
        for(int i=0;i<anzahl;++i)
        {
            vok[i] = tmp[i];  //übernimmt die Werte aus dem Zwischenspeicher
        }
        vok[anzahl].deu = d;  //schreibt in den letzten Wert die neue Vokabel
        vok[anzahl].engl = e;
        delete [] tmp;
    }
    

    da schreibst du uber die grenzen von vok. du hast nur anzahl vokabel reserviert also

    vok[anzahl].deu = d;  //schreibt in den letzten Wert die neue Vokabel
    

    ist um eines zu weit

    irgend etwas ist da ziemlich durcheinander. Vielleicht solltest du den ganzen code posten.
    K.



  • --> anzahl = 1;
    hatte ich glaub ich mal geschrieben, weil er sonst eine Fehlermeldung ausgab. Aber ich werds mal wieder zurücksetzen

    --> int zufall = rand()%(anzahl+1); //zufällige Vokabel-Nr
    müsste stimmen. Es soll eine zufällige Variable herauskommen die zwischen 0 und Anzahl(was ja der höchste Index des Arrays ist) liegt (einschließlich 0 und Anzahl). Und die Wertemenge von %(Anzahl+1) geht von 0 - Anzahl.

    -->und vor load() musst du anzahl wieder auf 0 setzen;
    hm... guck ich mir gleich mal an. Könnte gut sein.

    -->was mir noch auffält ist das du im construktor die variablen deu und engl anlegst. in den funktionen add, safe, load und abfrage aber auf vok zugreifst.
    Das ist nur, weil der hier gepostete Konstruktor veraltet ist. Hatte ihn zwischenzeitlich umgeändert nachdem ich "struct vokabel" angelegt hatte.

    -->da schreibst du uber die grenzen von vok
    Ich reserviere nach dem Erhöhen von Anzahl für vok neuen Speicher

    ++anzahl;
    vok = new vokabel[anzahl];
    


  • Wieso willst du eine Wertemenge von 0 bis Anzahl? Das sind dann eins mehr als es Elemente gibt und wenn du per Index auf das [Anzahl]-Element zugrifst, gibt's das doch gar nicht!



  • vieleicht ist der Name etwas ungünstig gewählt, aber für die Variable vok wird immer

    vok = new vokabel[anzahl];

    Speicher reserviert. Das heißt, sie hat den Index von 0 - Anzahl.

    /edit:

    oder hab ich das komplett falsch verstanden und man gibt in der Klammer nicht den höchsten Index, sondern die Anzahl an? ich glaub jetzt hats klick gemacht 😃

    /edit 2:

    hab ich wohl von VB so übernommen^^



  • Twister schrieb:

    vieleicht ist der Name etwas ungünstig gewählt, aber für die Variable vok wird immer

    vok = new vokabel[anzahl];

    Speicher reserviert. Das heißt, sie hat den Index von 0 - Anzahl.

    /edit:

    oder hab ich das komplett falsch verstanden und man gibt in der Klammer nicht den höchsten Index, sondern die Anzahl an? ich glaub jetzt hats klick gemacht 😃

    so ist es wenn du anzahl elemente reservierst dann kanns du auf die elemente 0 .. anzahl-1 zugreifen.
    K.



  • ok, ich werd dann mal den ganzen Code durchgehen und umändern 😃
    was mir aber grad noch aufgefallen ist:

    trainer()
    {
    	anzahl = 1;
    	ifstream in("vok.txt");
    	while(!in.eof())
    	{
    		char ch;
    		in>>ch;
    		if(ch == '\n') ++anzahl;
    		}
    	vok = new vokabel[anzahl];
    	in.close();
    	load();
    };
    

    Bei dem Konstruktor durchläuft er die if-Schleife nicht, die Anzahl erhöht. Daher wohl die ganzen Speicherfehler. Am Ende ist Anzahl immer 1 und es wird zu wenig Platz reserviert!
    Woran könnte das liegen?



  • das liegt daran das

    in>>ch;
    

    kein '\n' zurückgibt 🙂
    K.



  • hm... und was gibt er statt dessen zurück?

    Oder müsste ich das dann mit einem string auslesen, damit es funktioniert?



  • vielleicht so:

    #include <iostream>
    #include <fstream>
    
    int main() {
        int anzahl = 0;
        std::ifstream in("vok.txt");
        std::string s;
        char buffer[100];
        while(!in.eof())
        {
           in.getline(buffer,100);
           s = buffer;
           std::cout << s << std::endl;
           if ( s.length() ) anzahl++;
        }
        std::cout << anzahl << std::endl;
     }
    


  • thx 🙂

    habs jetzt so gemacht:

    while(!in.eof())
    {
    	char ch[100];
    	in.getline(ch,100);
    	++anzahl;
    }
    

    da 1 Reihe = 1 Vokabel(Deu + Engl) und er nach der letzten Reihe die while-Schleife verlässt, klappts so 🙂

    ich teste mal eben das komplette Prog durch, ob noch Fehler auftreten 😃



  • solange keine leeren zeilen in deinem file sind.
    K.



  • nö, kommen keine leeren Zeilen rein.

    Funktioniert nun auch alles. Danke für die Hilfe 🙂



  • nochmal eine kurze Frage:

    ich will das Prog jetzt als Stand-alone einrichten, damit auch Leute die kein vcpp haben es starten können.
    Allerdings wenn ich die exe (erstellen -> vokabeltrainer.exe erstellen) ausführe bleibt die Konsole leer.

    /edit:

    also wenn ich die Exe so starte... wenn ich sie aus vcpp raus starte ist alles normal.


Anmelden zum Antworten