Klassen / Zeigerfeld - Fehlerhafte Ausgabe



  • Ich glaub euch gern, dass das ganz recht grausig aussieht, wenn man ne Ahnung davon hat 😃

    Tatsächlich scheint mein Prof irgendwie an C zu hängen. Der Großteil seiner Folien scheint komplett auf C++ Elemente zu verzichten.
    Diese bringt er nur in der Theorie immer mal wieder ein, bemerkt dass das ganze ja sehr praktisch ist, aber weißt eigentlich kaum auf die grundsätzlichen Unterschiede hin.

    Ich habe auch noch nie was von vectors gehört... Mein ganzes Skript nutzt Zeiger im Prinzip auf die Weise wie ich oben (vielleicht aber wenigstens noch so dass es dann läuft 😉 )

    Kann man das Programm auf diese Weise noch irgendwie retten?
    (Wie erreiche ich also, dass ich in den cases 1 und 2 Objekte aus den entsprechenden Klassen erhalte und fülle und dann in 3 auf ebendiese zugreifen kann?)

    Oder sollte ich mir wirklich mal die Vektor-Variante anschauen und ist das aus einigermaßen gut zu verstehen und umzusetzen?
    Gedacht ist diese Aufgabe wohl ohne - da ich einfach noch nie was davon gehört habe - aber wenns dringend anzuraten ist, versuch ich mich da auch gerne.



  • wildschwein schrieb:

    Oder sollte ich mir wirklich mal die Vektor-Variante anschauen und ist das aus einigermaßen gut zu verstehen und umzusetzen?
    Gedacht ist diese Aufgabe wohl ohne - da ich einfach noch nie was davon gehört habe - aber wenns dringend anzuraten ist, versuch ich mich da auch gerne.

    Prinzipiell gilt dass ein std::vector immer einem rohen Array vorzuziehen ist. Und du hast mein volles Beileid: Viel zu oft bekommen Leute an Unis (o.ä.) "C mit cout" erklärt. Und da es "C mit cout" ist arbeitet man mit gefährlichen Arrays.



  • Frag doch mal deinen Professor, wo er C++ gelernt hat 😃

    wildschwein schrieb:

    Kann man das Programm auf diese Weise noch irgendwie retten?
    (Wie erreiche ich also, dass ich in den cases 1 und 2 Objekte aus den entsprechenden Klassen erhalte und fülle und dann in 3 auf ebendiese zugreifen kann?)

    Erste Notfallmaßnahme wäre es, nur einen Satz an Zeiger-Variablen zu verwenden (und die am besten so lokal wie möglich, d.h. für dich in der main()-Funktion). Allerdings benötigst du noch einiges mehr an Speicherverwaltung, um daraus etwas fehlerfreies machen zu können

    Oder sollte ich mir wirklich mal die Vektor-Variante anschauen und ist das aus einigermaßen gut zu verstehen und umzusetzen?

    Ja, das solltest du.

    Gedacht ist diese Aufgabe wohl ohne - da ich einfach noch nie was davon gehört habe - aber wenns dringend anzuraten ist, versuch ich mich da auch gerne.

    Es ist trotzdem besser, du gewöhnst dir frühzeitig einen vernünftigen Stil an, das erleichtert dir das Leben auch, wenn du mit dem Studium fertig bist und dieses Wissen in der Praxis anwenden darfst.


  • Mod

    wildschwein schrieb:

    Kann man das Programm auf diese Weise noch irgendwie retten?

    Retten nur in dem Sinne, dass man daraus etwas machen könnte, das bei vorsichtiger Behandlung eventuell nicht explodiert. Aber die Speicherlöcher sitzen zu tief, als dass man sie wirklich zuverlässig loswerden könnte. Da muss eine grundlegend andere Vorgehensweise her als Pointerfrickelei.

    (Wie erreiche ich also, dass ich in den cases 1 und 2 Objekte aus den entsprechenden Klassen erhalte und fülle und dann in 3 auf ebendiese zugreifen kann?)

    Es sollte reichen, wenn du in den case-Fällen deinen globalen Variablen das neue Feld zuweist anstatt neue Pointer anzulegen. Also student = new Student[anz] statt Student *student = new Student[anz] und beim Mitarbeiter ebenso. Das Programm hat dann aber immer noch andere Probleme.

    Oder sollte ich mir wirklich mal die Vektor-Variante anschauen und ist das aus einigermaßen gut zu verstehen und umzusetzen?

    So sähe eine robuste Lösung mit vector aus. Da kann eigentlich nichts schiefgehen, außer dass die Eingaben nicht auf Erfolg geprüft werden (d.h. wenn jemand einen Buchstaben eingibt, wo eine Zahl erwartet wird, passieren komische Dinge):

    #include<string>
    
    class Person
    {
    private:
      std::string Name;
    public:
      //  void setName(string N){Name=N;};
      // Da der Name sich wohl nicht ändern wird, schreiben wir das im 
      // Konstruktor und lassen den Setter mal lieber sein:
      Person(const std::string& name): Name(name) {}
    
      std::string getName(){return Name;}  // Nach Funktionen braucht kein Semikolon
    };
    
    class Mitarbeiter: public Person
    {
    public:
      Mitarbeiter(const std::string& name): Person(name) {}
    };
    
    class Student: public Person
    {
    public:
      Student(const std::string& name): Person(name) {}
    };
    
    // Globale Variablen lassen wir mal lieber ganz weg. Gibt nur Scherereien
    
    #include<iostream>
    #include<vector>
    using namespace std;
    
    int main(){
    
      bool end = false;   
    
      vector<Student> studenten;
      vector<Mitarbeiter> mitarbeiter;
    
      //Hauptmenü
      while(end==false)
        {
    
          cout<<"****Personendatenbank****"<<endl;
    
          int auswahl;
          cin>>auswahl;
    
          switch(auswahl)
            {
            case 1:
              {
                cout<<"Wie viele Mitarbeiter moechten Sie anlegen?"<<endl;
                int anz;
                cin>>anz;
                for(int i=0; i<anz; i++){
                  cout<<"\nBitte Name von Mitarbeiter "<<i+1<<" eingeben"<<endl;
                  string tempname;
                  cin>>tempname;
                  mitarbeiter.push_back(tempname); // hier wird der Konstruktor implizit aufgerufen
                }
                break;
              }
    
            case 2:
              {
                cout<<"Wie viele Studenten moechten Sie anlegen?"<<endl;
                int anz;
                cin>>anz;
                for(int i=0; i<anz; i++){
                  cout<<"\nBitte Name von Student "<<i+1<<" eingeben"<<endl;
                  string tempname;
                  cin>>tempname;
                  studenten.push_back(tempname);
                }      
                break;
              }
    
            case 3:
              {
                cout<<"Mitarbeiter:"<<endl;
                for(int i=0; i<mitarbeiter.size(); i++){
                  cout<<mitarbeiter[i].getName()<<endl;
                }
                cout<<"Studenten:"<<endl;
                for(int i=0; i<studenten.size(); i++){
                  cout<<studenten[i].getName()<<endl;}
                break;
              }
            } //switch ende
        } //while Ende
    }
    


  • Wow, danke für eure Antworten!
    Auch wenn ich die Funktionsweise von Vektoren noch nicht völlig verstehe, wirkt die Variante trotzdem deutlich angenehmer.
    Ich werde mich morgen mal ausführlicher damit beschäftigen und vielleicht auch nochmal mit meinem Übungsleiter drüber reden.

    Vielen Dank soweit 🙂



  • wildschwein schrieb:

    Wow, danke für eure Antworten!
    Auch wenn ich die Funktionsweise von Vektoren noch nicht völlig verstehe, wirkt die Variante trotzdem deutlich angenehmer.
    Ich werde mich morgen mal ausführlicher damit beschäftigen und vielleicht auch nochmal mit meinem Übungsleiter drüber reden.

    Vielen Dank soweit 🙂

    Den Kerl einfach hier vorbeischicken, den Rest kriegen wir schon hin 😉



  • So, nachdem ich mich jetzt nach einiger Zeit mit anderen Prioritäten mal wieder intensiv mit meiner kleinen Aufgabe hier auseinandersetzen konnte, möchte mich mich nochmal bedanken.

    Das Programm ist mittlerweile deutlich gewachsen und seitdem ich alles mit Vektoren schreibe, hatte ich keine größeren Pausen wegen unauffindbarer Fehler mehr und es läuft insgesamt ganz wunderbar.
    Mein Übungsleiter schein zwar zwischenzeitlich etwas verwirrt, als er keine guten alten Arrays gefunden hat und musste erstmal fragen, was ich denn da gemacht habe, ist aber doch sicher zufrieden, dass die Sache so schön läuft 😉

    An dieser Stelle habe ich nochmal eine Frage:
    Ich würde die Vektoren nun gerne auslesen, abspeichern und bei Programmstart wieder einlesen.
    Darüber habe ich bisher leider noch nie was gehört.
    Ich könnte mir vorstellen, dass das mit fprintf und irgendeiner Funktion, die die Textdatei dann wieder wie gewünscht verarbeitet, klappt.
    Ich würde mich freuen, wenn mir jemand kurz eine möglichst anfängerfreundliche Methode zeigen könnte - evtl genügt auch ein Stichwort oder ein Link.

    Die Frage hat ja nicht mehr allzu viel mit meinem ursprünglichen anliegen zu tun, wenns gewünscht wird kann ich auch gern nen neuen Thread erstellen.



  • wildschwein schrieb:

    mit fprintf

    Ist auch aus C. Nutze std::fstream :

    #include <fstream>
    int main()
    {
      std::ifstream Read("Filename.txt");
      //Von Read lesen
      Read.close(); //Bin mir nicht sicher ob nötig oder nicht
    
      std::ofstream Write("Filename.txt");
      //Nach Write schreiben
    }
    


  • EOutOfResources schrieb:

    #include <fstream>
    int main()
    {
      std::ifstream Read("Filename.txt");
      //Von Read lesen
      Read.close(); //Bin mir nicht sicher ob nötig oder nicht
    
      std::ofstream Write("Filename.txt");
      //Nach Write schreiben
    }
    

    Dafür hat uns der Herr Blöcke geschenkt.

    #include <fstream>
    int main()
    {
      {
        std::ifstream Read("Filename.txt");
        //Von Read lesen
      }//Schwuppduwupp, und Read ist weg. 
    
      std::ofstream Write("Filename.txt");
      //Nach Write schreiben
    }
    


  • volkard schrieb:

    Dafür hat uns der Herr Blöcke geschenkt.

    Ich finde unbedingte Scopes hässlich.



  • EOutOfResources schrieb:

    volkard schrieb:

    Dafür hat uns der Herr Blöcke geschenkt.

    Ich finde unbedingte Scopes hässlich.

    Dafür kann ich nicht aus Versehen von Read lesen, nachdem er geschlossen wurde.



  • volkard schrieb:

    Dafür kann ich nicht aus Versehen von Read lesen, nachdem er geschlossen wurde.

    Stimmt, daran habe ich nicht gedacht.



  • #include <fstream>
    int main()
    {
      std::ifstream Read("Filename.txt");
      //Von Read lesen
      Read.close(); //Bin mir nicht sicher ob nötig oder nicht
      #define Read (void)("dead name")
    
      std::ofstream Write("Filename.txt");
      //Nach Write schreiben
    }
    


  • Warum nicht read/write in freie Funktionen auslagern?



  • Danke für eure Antworten!

    Wenn ich nun mit ofstream eine Textdatei so beschreibe, dass in jeder Zeile genau ein Attribut(Strings bzw Integers) eines Elements meines Vektors steht, wobei für unterschiedliche Attribute unterschiedliche Dateien verwendet werden - wie kann ich diese wieder zeilenweise auslesen? Klappt das auch wenn ich Zahlen (in dieser Datei steht dann also nix anderes) direkt wieder als integer betrachten möchte?

    Bin bisher v.a. auf getline() gestoßen, aber ich werd um die Uhrzeit irgendwie nicht mehr recht schlau draus 😉



  • Ich würde die Daten auf jeden Fall nicht auf mehrere Dateien verteilen, sondern jedes Objekt "am Stück" (d.h. die einzelnen Attribute hintereinander) speichern. Dazu schreibst du dir z.B. zwei Methoden, die jeweils ein Element lesen bzw. schreiben können und kannst diese dann auf den gesamten vector<> anwenden (die hohe Kunst ist es, dafür die Stream-Operatoren zu überladen).


Anmelden zum Antworten