Programm stürzt nach korrekter Ausgabe ab.



  • @hustbaer ja genau falls man mal wissen möchte, wie es in so ganz alten programmen aussehen könnte und die netten modernen features nicht zur verfügung stehen.

    dass man das bei neuen projekten ein bisschen anders machen könnte, weiß ich auch, aber allgemein ist man in den unternehmen wohl nicht so begeistert, wenn da irgendson absolvent kommt und meint, dass man das programm, an dem die letzten 20 jahre gearbeitet wurde, ja einfach mal neu und viel besser und unkomplizierter machen könnte.

    jedenfalls hat man uns damals so erklärt, warum wir eigentlich C mit erweiterungen lernen.


  • Mod

    Das hat weniger mit "alt" gegen "modern" zu tun und mehr mit "gut" gegen "scheiße". Die Idee von Ressourcenhaltung mittels spezieller Klassen, Trennung von Zuständigkeiten, etc. sind nun wahrlich keine neuen Ideen. Diese Ideen sind sogar deutlich älter als C++ selber (und C++ ist uralt!). Tatsächlich war die treibende Hauptidee hinter C++, dass man ein Framework für C wollte, mit dem man diese Ideen in C mit wenig Aufwand umsetzen kann (Denn ein guter Programmierer programmiert auch in C auf diese Weise. Es ist bloß recht viel Schreibarbeit, die man sich in C++ sparen kann). Es gibt und gab halt trotzdem viele Leute, die es einfach nicht drauf haben und in egal welcher Sprache nur Mist produzieren.

    Dass sich das in modernen Zeiten besser anfühlt, mag daran liegen, dass mittlerweile die Fraktion derer, die kapiert haben, wie C++ gedacht ist, so überwältigend laut ist, dass man schon echt hinterm Wald wohnen muss, um den Schuss nicht gehört zu haben. Wie offenbar der Prof, der hinter dieser Aufgabe steht.



  • @Quiche-Lorraine Danke, habs mir angeguckt. Ich versuch so viel wie möglich mitzunehmen. Nur grade hab ich gefühlt einen Tiefpunkt beim Lernen erreicht. Ich hab viel mit den Unterlagen aus der Vorlesung und parallel mit einem Buch gearbeitet. Dabei lief es gefühlt auch ganz gut (nebenbei auch immer mal was geschrieben, anstatt nur zu lesen). Jetzt mit den Aufgaben fühlt es sich aber eher so an, als wenn ich gar nichts verstanden habe 😅

    @SeppJ Ich verstehe wirklich nicht, wie du dich die ganze Zeit an dieser einen Aufgabe so aufziehen kannst. Zudem ist es doch auch recht anmaßend, wie du dich über den Prof äußerst. Was nicht heißt, dass ich hier jemanden in Schutz nehmen möchte. Nur reicht ein kleiner Ausschnitt aus einer Aufgabenstellung meiner Meinung nach nicht aus, um sich ein vernünftiges Urteil über die Art und Weise, wie jemand lehrt zu bilden.



  • @Sedna sagte in Programm stürzt nach korrekter Ausgabe ab.:

    Nur reicht ein kleiner Ausschnitt aus einer Aufgabenstellung meiner Meinung nach nicht aus, um sich ein vernünftiges Urteil über die Art und Weise, wie jemand lehrt zu bilden.

    Doch, der Ausschnitt reicht völlig.



  • @Sedna sagte in Programm stürzt nach korrekter Ausgabe ab.:

    Jetzt mit den Aufgaben fühlt es sich aber eher so an, als wenn ich gar nichts verstanden habe

    Frag einfach nach, wenn du bestimmte Dinge nicht verstanden hast! Wie du gemerkt hast, ging die gesamte Kritik hier bisher auch an die Aufgabe/den Aufgabensteller, nicht an dich. Gut, immerhin lernst du jetzt wenigstens gleich, warum das so keine gute Idee ist 😉

    Ich verstehe wirklich nicht, wie du dich die ganze Zeit an dieser einen Aufgabe so aufziehen kannst.

    Das liegt daran, dass viel zu viele Studenten das eben genau so lernen, weil es eben so gelehrt wird. Und man dann jedem neuen Entwickler erst einmal erklären muss, dass das so NICHT gemacht wird, wenn man ordentlich arbeiten will. Und erfahrungsgemäß ist die nächste Aufgabe eben nicht "wie macht man es besser", sondern was ganz anderes. Vielleicht auch, weil in der Veranstaltung eigentlich gar nicht C++ gelehrt werden soll, sondern nur irgendeine Sprache als Mittel zum Zweck verwendet wird und zufällig altes Lehrmaterial für C++ rumlag. Nur wird man, wenn man so in C++ arbeitet, schnell Probleme bekommen.



  • Ich verstehe @SeppJ s Aufregung schon. Ich hab einige Arbeitskollegen die grosse Augen bekommen und neugierig fragen "ja wie macht man das denn sonst" wenn ich anmerke dass es Sch*** ist in einer Klasse direkt 2, 3, 5, 10 Resourcen zu besitzen. Allein schon weil den Ctor leak-frei und exceptionsicher zu bekommen ein Albtraum ist.


  • Gesperrt

    @SeppJ sagte in Programm stürzt nach korrekter Ausgabe ab.:

    dem TE einfach die Hausaufgaben zu machen, aber eben mit einem selbstgeschriebenem Vector als unterliegender Datenstruktur

    Das seh ich auch so... Hier wäre mein Vorschlag mit char * anstatt string und ohne vector:

    #include <cstring>
    #include <iostream>
    using namespace std;
    
    class Student
    {
    public:
        Student(const char *name, int matrikelnummer, int semester)
        {
            this->name = new char[strlen(name)];
            for (size_t i = 0; name[i]; i++)
            {
                this->name[i] = name[i];
            }
            this->matrikelnummer = matrikelnummer;
            this->semester = semester;
        }
        ~Student()
        {
            delete this->name;
            this->name = nullptr;
            this->matrikelnummer = 0;
            this->semester = 0;
        }
        Student(const Student &s)
        {
            this->name = new char[strlen(s.name)];
            for (size_t i = 0; s.name[i]; i++)
            {
                this->name[i] = s.name[i];
            }
            this->matrikelnummer = s.matrikelnummer;
            this->semester = s.semester;
        }
        void setSemester(int semester)
        {
            this->semester = semester;
        }
        friend ostream &operator<<(ostream &os, const Student &s);
    
    private:
        char *name;
        int matrikelnummer;
        int semester;
    };
    ostream &operator<<(ostream &os, const Student &s)
    {
        os << s.name << " ; " << s.matrikelnummer << " ; " << s.semester;
        return os;
    }
    
    void printKlausAndGundula()
    {
        Student stud = Student("Kleber, Klaus", 1234, 1);
        Student stud2 = Student("Gauss, Gundula", 5678, 1);
        Student stud3 = stud2;
        stud2.setSemester(3);
        cout << stud << endl;
        cout << stud2 << endl;
        cout << stud3 << endl;
    }
    
    int main()
    {
        while (true)
        {
            printKlausAndGundula();
        }
    }
    


  • @EinNutzer0
    Hast du den Code mal laufen lassen? Das sollte wunderschön wegcrashen so wie du es hier gepostet hast.

    EDIT: Ne, sorry, du musst noch ein bisschen was ändern damit es crasht.
    EDIT2: strlen Bug übersehen, d.h. ja doch, hat auch so gutes Crash-Potential.



  • Das behebt jetzt genau 1 Problem, nämlich dass die Namen der Studenten erhalten bleiben, wenn du bei strlen + 1 nicht vergessen hättest (nebst kopieren des Nullbytes). Wozu eine Library-Funktion wie strcpy nutzen, wenn man es auch selbst falsch nachimplementieren kann und wenn es mit std::string 1000x einfacher wäre?

    Rule of Zero / Three / Five?

    ~Student()
        {
            delete this->name;
            this->name = nullptr;
            this->matrikelnummer = 0;
            this->semester = 0;
        }
    

    Das sind absolut nutzlose 3 Zeilen überflüssiger und entbehrlicher Code, der nutzlos ist und weder gebraucht noch verwendet wird 😉

    Und außerdem: die zum Kleber-Claus gehörige Gundula heißt "Gause".


  • Gesperrt

    Habe noch einen Default Constructor hinzufügt:

    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    class Student
    {
    public:
        Student() : Student("default constructor", 1, 1)
        {
        }
        Student(const char *name, int matrikelnummer, int semester)
        {
            this->name = new char[strlen(name) + 1];
            for (size_t i = 0; name[i]; i++)
            {
                this->name[i] = name[i];
            }
            this->matrikelnummer = matrikelnummer;
            this->semester = semester;
        }
        ~Student()
        {
            delete this->name;
            this->name = nullptr;
            this->matrikelnummer = 0;
            this->semester = 0;
        }
        Student(const Student &s)
        {
            this->name = new char[strlen(s.name)];
            for (size_t i = 0; s.name[i]; i++)
            {
                this->name[i] = s.name[i];
            }
            this->matrikelnummer = s.matrikelnummer;
            this->semester = s.semester;
        }
        void setSemester(int semester)
        {
            this->semester = semester;
        }
        friend ostream &operator<<(ostream &os, const Student &s);
    
    private:
        char *name;
        int matrikelnummer;
        int semester;
    };
    ostream &operator<<(ostream &os, const Student &s)
    {
        os << s.name << " ; " << s.matrikelnummer << " ; " << s.semester;
        return os;
    }
    
    void printKlausAndGundula()
    {
        const int n = 5000;
        Student stud = Student("Kleber, Klaus", 1234, 1);
        Student stud2 = Student("Gauss, Gundula", 5678, 1);
        Student stud3 = stud2;
        stud2.setSemester(3);
        cout << stud << endl;
        cout << stud2 << endl;
        cout << stud3 << endl;
        Student studarr[n];
        for (size_t i = 0; i < n; i++)
        {
            int r = rand() / (RAND_MAX / 3);
            switch (r)
            {
            case 0:
                studarr[i] = stud;
                break;
            case 1:
                studarr[i] = stud2;
                break;
            case 2:
                studarr[i] = stud3;
                break;
            default:
                break;
            }
        }
        cout << studarr[0] << endl;
        cout << studarr[1] << endl; // Aborted (Speicherabzug geschrieben)
        cout << studarr[n - 2] << endl;
        cout << studarr[n - 1] << endl;
    }
    

    Es crasht und ich weiß nicht wieso? 😞 Habe auch + 1 hinzugefügt...



  • @EinNutzer0

    studarr[i] = stud;

    Dadurch wird der Speicher von name am Ende zweimal freigegeben.



  • @EinNutzer0 dein eigenes strcpy() kopiert die '\0' am Ende nicht.


  • Gesperrt

    Danke, nu funktioniert s, es ist aber noch nicht richtig, hab das delete entfernt...

    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <memory>
    using namespace std;
    
    class Student
    {
    public:
        Student() : Student("default constructor", 1, 1)
        {
        }
        Student(const char *name, int matrikelnummer, int semester)
        {
            this->name = new char[strlen(name) + 1];
            strcpy(this->name, name);
            this->matrikelnummer = matrikelnummer;
            this->semester = semester;
        }
        ~Student()
        {
    
            this->name = nullptr;
            this->matrikelnummer = 0;
            this->semester = 0;
        }
        Student(const Student &s)
        {
            this->name = new char[strlen(s.name) + 1];
            strcpy(this->name, s.name);
            this->matrikelnummer = s.matrikelnummer;
            this->semester = s.semester;
        }
        void setSemester(int semester)
        {
            this->semester = semester;
        }
        friend ostream &operator<<(ostream &os, const Student &s);
    
    private:
        char *name;
        int matrikelnummer;
        int semester;
    };
    ostream &operator<<(ostream &os, const Student &s)
    {
        os << s.name << " ; " << s.matrikelnummer << " ; " << s.semester;
        return os;
    }
    
    void printKlausAndGundula()
    {
        const int n = 5000;
        Student stud = Student("Kleber, Klaus", 1234, 1);
        Student stud2 = Student("Gauss, Gundula", 5678, 1);
        Student stud3 = stud2;
        stud2.setSemester(3);
        cout << stud << endl;
        cout << stud2 << endl;
        cout << stud3 << endl;
        Student studarr[n];
        for (size_t i = 0; i < n; i++)
        {
            int r = rand() / (RAND_MAX / 3);
            switch (r)
            {
            case 0:
                studarr[i] = stud;
                break;
            case 1:
                studarr[i] = stud2;
                break;
            case 2:
                studarr[i] = stud3;
                break;
            default:
                break;
            }
        }
        cout << studarr[0] << endl;
        cout << studarr[1] << endl; // Aborted (Speicherabzug geschrieben)
        cout << studarr[n - 2] << endl;
        cout << studarr[n - 1] << endl;
    }
    

    @manni66 sagte in Programm stürzt nach korrekter Ausgabe ab.:

    Dadurch wird der Speicher von name am Ende zweimal freigegeben

    Daran wird es liegen...


  • Gesperrt

    @wob sagte in Programm stürzt nach korrekter Ausgabe ab.:

    Und außerdem: die zum Kleber-Claus gehörige Gundula heißt "Gause"

    Ja tut mir leid, schau kein ZDF 😋



  • Durch das Entfernen des delete hast du ein Memory Leak.
    Und es muss delete[] this->name; lauten, denn du allozierst ja ein Array.

    Wenn du mal in The rule of three/five/zero schaust, dann wirst du sehen, daß dir noch eine Operation fehlt, welche du implementieren mußt (Hint: Copy-and-swap).

    Und da du (dann) sicherlich bemerkt hast, daß das viel zu viel Arbeit für eine relativ einfache Funktionalität ist, solltest du dir unbedingt RAII aneignen, d.h. wenn schon nicht die std:.string benutzt wird, dann wenigstens eine eigene Helperklasse benutzen, welche Ressourcenerzeugung und -löschen durchführt (das dann auch wieder exceptionsicher ist).


  • Gesperrt

    ja... zu komplex, du hast recht... Genug für heute, bis morgen!



  • @EinNutzer0 btw: eine Matrikelnummer ist keine Ganzzahl (int), auch wenn sie so aussieht.

    Nein, ein unsigned int ist es auch nicht.

    Du rechnest schließlich nicht damit. (Ist eine Differenz von Matrikelnummern sinnvoll?)


  • Gesperrt

    @DirkB Das ist ja kein Programm für einen echten Anwendungsfall, vielmehr soll string vermieden werden und später irgendwann auch Vermeidung des vectors. 😞

    Quasi ein Entwurf, mit dem @Sedna weiter machen kann...


  • Mod

    @EinNutzer0 : Du machst ja konsequent genau das, was hier im Thread an der Aufgabenstellung kritisiert wurde. Kein Wunder, dass das nicht läuft und viele Fehler hat, denn die Kritik an der Aufgabenstellung ist schließlich, dass sie zu einem fehleranfälligem Stil führt. Sicher erfüllst du so den Wortlaut der Aufgabenstellung, aber setz dich doch darüber hinweg und mach es "richtig", so dass der Fragesteller sehen kann, dass das Programm dann auf Anhieb korrekt ist und viel schöner anzusehen ist.



  • Oder gib zwei Lösungen ab. Einmal die, die der Dozent erwartet und zeigt, wie man´s nicht macht und die, die std::string benutzt und es richtig macht.


Anmelden zum Antworten