problem mit fstream



  • t1m0n schrieb:

    CStoll schrieb:

    Wenn du noch einen Tag wartest - in der nächsten Ausgabe des C++-Magazins kommt auch ein Artikel zu vector<> und anderen Containerklassen der STL.

    Isat das Magazin denn OpenSource? Habe eine ältere Ausgabe im Fachhandel gesehen, kostete allerdings 10€ und das finde ich ist ein wenig viel oder?

    Das Magazin findest du hier an Bord - Magazin - die Artikel

    Aber wozu benötige ich jetzt die Vektoren? Mit deiner schleife kann ich das doch alles ausgeben lassen oder?

    Wenn du mehr machen willst als ein- und ausgeben (z.B. die Datensätze sortieren), mußt du deine Daten irgendwo intern zwischenspeichern.

    Mir gibt die Konsole nun folgendes aus: 97509851100529949-1
    Ich habe das einlesen so gestalltet:

    //Auslesen der Datei
             ifstream lesen;
             lesen.open(dateiadresse.c_str());
             while (lesen)
             {
             cout << lesen.get();
             }
             lesen.close();
    

    [/quote]get() gibt einen int zurück (-1 steht übrigens für EOF), wenn du etwas lesbareres haben willst, mußt du das zumindest nach char casten. Oder du liest dir den Thread nochmal aufmerksam durch und denkst etwas länger über operator>> nach.



  • CStoll schrieb:

    tmp ist ein Objekt vom Typ "schueler" - dort kannst du alle eingelesenen Daten des Schülers zusammenfassen (nächste Steigerung des Codes wäre es übrigens, für "schueler" und "noten" einen eigenen operator>> und operator<< zu definieren).

    Die Formatierung bekommst du hin, indem du nicht per get() jedes Zeichen einzeln ausliest, sondern über die Stream-Operatoren die Werte einliest und direkt in den richtigen Typ parsen lässt.

    Ich glaube du willst darauf hinaus. Ich kenne aber nicht solche Operatoren. Ich habe das übrigens nun so umgeschrieben

    schreiben << a.nachname << " " << a.n.deutsch;
    

    Dort habe ich ja auch den << Operator. Hängt das irgendwie zusammen mit dem worauf du hinaus willst??



  • Ja, das ist schonmal ein Anfang. Nun mußt du die Daten nur noch passend dazu einlesen:

    lesen >> a.nachname >> a.n.deutsch;
    

    (und bei der Ausgabe würde ich noch ein "\n" hinterherschieben, dann sieht deine Datei übersichtlicher aus)



  • Ok, das mit dem \n verstehe ich, danke für den Hinweis.
    Aber woher soll mein Programm denn beim Einlesen wissen was a.nachname oder a.n.deutsch ist? Ich gehe davon aus, das die Laufzeit beendet ist und die Datei nach x-Tagen wieder eingelesen wird.
    Ich möchte, dass halt nicht nur von einer Person alles gespeichert wird, sondern das die TXT-Datei erweitert werden kann. Also n-viele Schüler in der txt verwaltet werden können.



  • t1m0n schrieb:

    Aber woher soll mein Programm denn beim Einlesen wissen was a.nachname oder a.n.deutsch ist? Ich gehe davon aus, das die Laufzeit beendet ist und die Datei nach x-Tagen wieder eingelesen wird.

    Dazu mußt du beim Schreiben die Reihenfolge festlegen, in der die Daten in der Datei landen und später in der selben Reihenfolge wieder auslesen (das Leerzeichen und Newline werden von op>> als Trennzeichen zwischen den einzelnen Werten angesehen).

    (im Klartext: DU weißt, daß in der Datei erst der Name und dann die zugehörige Deutsch-Note kommt. Also mußt du die Elemente auch in genau dieser Reihenfolge wieder lesen)



  • Ok. Es klappt nicht. Habe das gefühl es liegt daran das eine methode oder so wieder fehlt^^

    ifstream lesen;
             lesen.open(dateiadresse.c_str());
             while (lesen)
             {
             lesen >> a.nachname >> a.n.deutsch;
             }
             lesen.close();
    

    Und was das Schreiben angeht, habe ich das so gemacht:

    //Schreiben der Datei
             ofstream schreiben;
             schreiben.open(dateiadresse.c_str(), ios_base::app);
             schreiben << a.nachname << " " << a.n.deutsch << "\n";
             schreiben.close();
    

    Das Schreiben funktioniert einwandfrei. In der txt steht alles drinne wie es soll, aber auslesen tut er rein garnix.



  • Natürlich liest er aus - allerdings überschreibt er in jedem Schleifendurchlauf die gelesenen Werte wieder neu. Das heißt, wenn du mit den Daten weiterrechnen willst, mußt du das in der while()-Schleife erledigen.



  • CStoll schrieb:

    Natürlich liest er aus - allerdings überschreibt er in jedem Schleifendurchlauf die gelesenen Werte wieder neu. Das heißt, wenn du mit den Daten weiterrechnen willst, mußt du das in der while()-Schleife erledigen.

    Ich möchte sie nicht großartig weiterverarbeiten, sondern lediglich ausgeben, so dass der Benutzer weiß welche Daten in der txt schon vorhanden sind und keine doppelt abspeichert.



  • Das mußt du auch in der Schleife erledigen:

    while (lesen)
    {
      lesen >> a.nachname >> a.n.deutsch;
      cout << "Name: " << a.nachname << "\nNote Deutsch: " << a.n.deutsch << endl;
    }
    

    (das endl schreibt ein \n und sorgt dafür, daß die Daten sofort auf dem Bildschirm landen)



  • Komisch..
    Bei mir gibt er nun den letzten Datensatz doppelt aus.

    //Auslesen der Datei
             ifstream lesen;
             lesen.open(dateiadresse.c_str());
             while (lesen)
             {
             lesen >> a.nachname >> a.n.deutsch;
             cout << "Nachname: " << a.nachname << endl 
                  << "Deutsch-Note: " << a.n.deutsch;
             cout << endl;
             }
    

    Es steht zwar nur:
    mueller 2
    muellerneu 3
    drinne aber er schreibt die letzte Zeile zweimal.. wieso?



  • Wenn die Anweisung "lesen>>..." auf's Dateiende stößt, bleibt die Zielvariable unverändert - wenn dich die letzte Zeile stört, mußt du die Schleife vorher verlassen (dazu benötigst du ein "if(!lesen) break;" vor dem cout (auf Deutsch: Wenn "lesen" nicht mehr bereit ist, verlasse die Schleife)).



  • CStoll schrieb:

    Wenn die Anweisung "lesen>>..." auf's Dateiende stößt, bleibt die Zielvariable unverändert - wenn dich die letzte Zeile stört, mußt du die Schleife vorher verlassen (dazu benötigst du ein "if(!lesen) break;" vor dem cout (auf Deutsch: Wenn "lesen" nicht mehr bereit ist, verlasse die Schleife)).

    Klappt nicht. Ich habe es wie folgt eingebunden:

    //Auslesen der Datei
             ifstream lesen;
             lesen.open(dateiadresse.c_str());
             while (lesen)
             {
             lesen >> a.nachname >> a.n.deutsch;
             cout << "Nachname: " << a.nachname << endl 
                  << "Deutsch-Note: " << a.n.deutsch;
             cout << endl;
             if(!lesen) //Um die Schleife zu verlassen bevor nicht weiter gelesen werden kann, dient dazu die doppelte Ausgabe der letzten Zeile zu vermeiden
             {
                        break; 
             }
             }
             lesen.close();
    


  • wlkikiv 😃 - ich sagte VOR dem cout:

    while(lesen)
    {
      lesen>>...;
      if(!lesen) break;
      cout<<...;
    }
    


  • Achso, danke 🙂
    wer lesen kann ist klar im vorteil 💡



  • Wie kann man prüfen ob eine Variable gesetzt ist?
    Ich möchte nun prüfen ob dateiadresse bereits mit einer Adresse initialisiert wurde. Wenn nicht soll eine eingabeaufforderung kommen.
    Geht das vielleicht mit

    if(!dateiadresse)
    

    😕



  • Ob eine Variable gesetzt ist kannst Du nicht herausfinden. Du kannst nur schauen ob ein bestimmter Wert enthalten ist (eine nicht-gesetzte, sprich uninitialisierte Variable enthält Müll, bzw. bei Objekten Defaults).

    Du kannst aber überprüfen ob einer Variable vom Typ std::string eine Sequenz zugewiesen wurde:

    if (!dateiadresse.empty())
    


  • Ok, hab es angewandt und mein Programm etwas erweitert. Nun sagt der Debugger allerdings:

    jump to case label

    und verweist auf die Zeile wo

    case 2:
    

    steht. Mein Programm sieht so aus:

    #include <iostream>
    #include <string>
    #include <fstream>
    using namespace std;
    
    //Die Noten-Klasse
    class noten
    {
          public:
                 int deutsch;
                 int englisch;
                 int mathe;
                 int technik;
    };
    
    //Die Schüler-Klasse
    class schueler
    {
          public:
                 string nachname;
                 string vorname;
                 string strasse;
                 int plz;
                 string ort;
                 noten n;
    };
    
    int main(void)
    {
        int option;
        cout << "##############################" << endl
             << "Bitte waehlen Sie eine Option:" << endl << endl
             << "(1) Datei auslesen" << endl
             << "(2) Datei schreiben" << endl
             << "##############################" << endl; 
        cin >> option;
        switch(option)
        {
        case 1:
              schueler a;
              char neu;
    
              //Angabe des Dateipfads
              string dateiadresse;
              cout << "Bitte geben Sie die Adresse der Datei ein: ";
              cin >> dateiadresse;
    
              //Auslesen der Datei
              ifstream lesen;
              lesen.open(dateiadresse.c_str());
              while (lesen)
              {
              lesen >> a.nachname >> a.vorname >> a.strasse >> a.plz >> a.ort >> a.n.deutsch >> a.n.englisch >> a.n.mathe >> a.n.technik;
    
              //Um die Schleife zu verlassen bevor nicht weiter gelesen werden kann, dient dazu die doppelte Ausgabe der letzten Zeile zu vermeiden
              if(!lesen) break;
    
              //Auslesen der Datei         
              cout << "Nachname: " << a.nachname << endl
                   << "Vorname: " << a.vorname << endl
                   << "Strasse: " << a.strasse << endl
                   << "Postleitzahl: " << a.plz << endl
                   << "Ort: " << a.ort << endl
                   << "Deutsch-Note: " << a.n.deutsch << endl
                   << "Englisch-Note: " << a.n.englisch << endl
                   << "Mathematik-Note: " << a.n.mathe << endl
                   << "Technologie-Note: " << a.n.technik << endl;
              cout << endl;
              }
             lesen.close();
             break;
        case 2:
              if(!dateiadresse.empty())
              {
               //Angabe des Dateipfads
               string dateiadresse;
               cout << "Bitte geben Sie die Adresse der Datei ein: ";
               cin >> dateiadresse;
              }
              do
              {         
              //Eingabe der Daten für die Schüler-Klasse
              cout << "Nachname: ";
              cin >> a.nachname;
              cout << "Vorname: ";
              cin >> a.vorname;
              cout << "Strasse: ";
              cin >> a.strasse;
              cout << "Postleitzahl: ";
              cin >> a.plz;
              cout << "Ort: ";
              cin >> a.ort;
    
              //Eingabe der Daten für die Noten-Klasse
              cout << "Deutsch-Note: ";
              cin >> a.n.deutsch;
              cout << "Englisch-Note: ";
              cin >> a.n.englisch;
              cout << "Mathematik-Note: ";
              cin >> a.n.mathe;
              cout << "Technologie-Note: ";
              cin >> a.n.technik;
    
              //Schreiben der Datei
              ofstream schreiben;
              schreiben.open(dateiadresse.c_str(), ios_base::app);
              schreiben << a.nachname << "\n" 
                        << a.vorname << "\n"
                        << a.strasse << "\n"
                        << a.plz << "\n"
                        << a.ort << "\n"
                        << a.n.deutsch << "\n"
                        << a.n.englisch << "\n"
                        << a.n.mathe << "\n"
                        << a.n.technik << "\n";
              schreiben.close();
    
              //Wiederholung der Schleife falls erwünscht
              cout << "Moechten Sie einen weiteren Schueler hinzufuegen?" << endl 
                   << "Antworten Sie bitte mit j fuer ja oder n fuer nein: ";
              cin >> neu;
              break;
              };
              }while(neu=='j');
        return 0;
    }
    


  • Lies dir doch mal die vollständige Meldung durch - ich tippe auf "jump to case label bypasses variable initializing" (oder so). Du solltest die Variablen besser nicht im switch() definieren, sondern davor - andernfalls wird der Konstruktor-Aufruf übergangen, wenn du bei einer anderen case-Marke landest.



  • Komplett siehts so aus:

    72 D:\Desktop-Save\c++\Aufträge + Übungen\302 Schuelerverwaltung2\schuelerverwaltung2.cpp jump to case label

    Von welcher Variable redest du?
    Die zu überprüfende wird doch vor switsch definiert.



  • Lies einfach in der nächsten Zeile weiter 😉

    Und das Problem dürfte die Variable "dateiadresse" sein - wenn option==2 ist, überspringst du die Initialisierung (und die Abfrage des Dateinamen)


Anmelden zum Antworten