[Anfänger sucht Hilfe] Personalverwaltung - Datenerfassung und Ausgabe



  • Hallo,

    wie man sieht bin ich völlig neu hier im Board. Ich arbeite seit einiger Zeit schon mit Python. Nun hab ich mich ran gemacht C++ zu lernen, bisher über learncpp.com, das dortige Tutorial war/ist auch ganz gut, im Moment bin ich so bei Lektion 6/7.

    Da es mir früher schon sehr geholfen hat, hab ich einfach mal bisl angefangen was selber zu machen. Im Prinzip nur ein Shell-Programm. Jetzt komm ich allerdings nicht mehr so richtig weiter.

    Folgendes:
    Ich will einfach nur Personaldaten erfassen (erstmal), also Name, Vorname, Arbeitsstunden. Das ganze läuft im Moment über ein struct und die Daten werden mit getline in C-Arrays gepackt.

    Das geht jedoch im Moment nur für 1 Person. Jetzt suche ich allerdings einen Weg, wie ich mehrere Personen eingeben und danach direkt als "Tabelle" ausgeben kann. In Python würde ich einfach Listen (die Daten) in eine Liste packen und ausgeben. Kann man sowas in C++ auch nachstellen, also structs in eine Liste packen oder so?

    Anbei noch ein wenig Code.

    Das struct:

    struct PersonInfoStruct
    {
    //    int index;
        char name[21];
        char surname[21];
        float hours;
    };
    
    PersonInfoStruct Person;
    

    Das Person-Anlegen:

    void sub_new_person()
    {
        cout << "\t -------------------------------------- " << endl;
        cout << "\t|          Personalverwaltung          |" << endl;
        cout << "\t|       - Mitarbeiter anlegen -        |" << endl;
        cout << "\t -------------------------------------- " << endl;
        clear_display(2);
    
        // get line takes otherwise the \n from last menu
        cin.ignore(1, '\n');
    
        cout << "\tGeben Sie den Vornamen ein: ";
        cin.getline(Person.name, 20);
    
        cout << "\tGeben Sie den Nachnamen ein: ";
        cin.getline(Person.surname, 20);
    
        //TODO: WIE ABFRAGE AUF ZAHLEN PRÜFEN - unsicheres cin?!
        cout << "\tGeben Sie die Arbeitsstunden ein: ";
        cin >> Person.hours;
    }
    

    Und die bisherige Ausgabe, hier wird sicher mal noch eine for-Schleife oder ähnliches nötig um eben mehrere Personen auszugeben:

    int sub_personal()
    {
        bool repeat = true;
    
    // TODO: Auflistung mehrerer Struct-Daten ermöglichen
        do
        {
            cout << "\t -------------------------------------- " << endl;
            cout << "\t|          Personalverwaltung          |" << endl;
            cout << "\t -------------------------------------- " << endl;
            cout << "\t                                        " << endl;
            cout << "\t Vorname        Nachname        Stunden "
            cout << "\t  " << Person.name << " " << Person.surname << " | " << Person.hours << endl;
            cout << "\t                                        " << endl;
            cout << "\t -------------------------------------- " << endl;
            cout << "\t    <1>: Neu | <2>: Löschen | <3>: Ändern     " << endl;
            cout << "\t       <4>: Zurück zum Hauptmenü          " << endl;
            cout << "Eingabe: ";
    
            char input;
            cin >> input;
    
            //ergänze: buchstaben eingabe immer zu klein wandeln
    
            switch(input)
            {
                case '1':
                    sub_new_person();
                    break;
                case '2':
                    sub_del_person();
                    break;
                case '3':
                    cout << "Hier kommt ändern!" << endl;
                    break;
                case '4':
                    show_main_menu();
                    // Beenden des Sub_Programms durch false der while Bedingung!
                    repeat = false;
                    break;
                default:
                    cout << "Ungültige Eingabe! Bitte nochmal versuchen!" << endl;
            }
        }
        while (repeat);
    }
    

    Für jede Hilfe bin ich dankbar, sagt mir auch ruhig, dass ich aufm Holzweg bin. 😉

    AlphaX2



  • Dafür kannst du vectoren nutzen.

    #include <vector>
    
    std::vector<PersonInfoStruct> personen;
    

    Außerdem solltest du in deiner struct keine char-Arrays benutzen, nimm lieber std::string.



  • Eventuell hilft dir das hier weiter:

    http://www.c-plusplus.net/forum/p2232268#2232268


  • Mod

    AlphaX2 schrieb:

    Das geht jedoch im Moment nur für 1 Person. Jetzt suche ich allerdings einen Weg, wie ich mehrere Personen eingeben und danach direkt als "Tabelle" ausgeben kann. In Python würde ich einfach Listen (die Daten) in eine Liste packen und ausgeben. Kann man sowas in C++ auch nachstellen, also structs in eine Liste packen oder so?

    Ja und wie! Vergiss einfach diesen C/C++-Mischmasch. In "richtigem" C++ ist das total einfach:

    (Ungetestet)

    #include <string>
    #include <vector>
    #include <iostream>
    #include <limits>
    
    struct PersonInfoStruct  // Ich würde bei Typennamen nicht angeben, dass es ein struct ist. Wozu soll das gut sein?
    {
      // Hier sollte man überlegen, ob die Attribute nicht lieber private sein sollten.
      std::string name;   // Vergiss char-Arrays, außer du hast einen sehr guten Grund
      std::string surname;
      float hours;
    };
    
    // Deine sub_new_person schreiben wir ein bisschen um und nennen sie anders:
    std::istream& operator>>(std::istream& in, PersonInfoStruct& person)
    {
        std::cout << "\tGeben Sie den Vornamen ein: ";  // Naja, eigentlich sollte eine Eingabefunktion nix ausgeben, aber ich will nicht alles umbauen
        getline(person.name, in);
    
        std::cout << "\tGeben Sie den Nachnamen ein: ";
        getline(person.surname, in);
    
        std::cout << "\tGeben Sie die Arbeitsstunden ein: ";
        in >> person.hours;
    
        in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        return in;
    } 
    
    // Ausgabe gibt's auch noch dazu:
    std::ostream& operator<<(std::ostream& out, const PersonInfoStruct& person)
    {
        return out << "Vorname: " << person.name
                   << "\nNachname: " << person.surname
                   << "\nArbeitsstunden: " << person.hours << '\n';
    } 
    
    int main()
    {
      // Wenn man das so gemacht hat, dann ist das Hauptprogramm sehr übersichtlich: 
      std::vector<PersonInfoStruct> personenliste;
      for (PersonInfoStruct person; std::cin >> person; personenliste.push_back(person));
    
      std::cout << "Folgende Personen sind bekannt:\n";
      for (auto person : personenliste)
        std::cout << person << '\n';
    }
    

    http://ideone.com/vHVCX



  • Jo, SeppJ's Programm macht dasselbe wie meins (Telefonnummer <-> Arbeitsstunden).
    Dafür speichert meins aber auch gleich die Daten in ner Datei ab, sodass sie beim nächsten Start des Programms noch da sind.
    Das macht das Löschen/Ändern natürlich ein wenig interessanter, kannst dir ja was einfallen lassen.



  • Das ist ja überwältigend wie schnell man hier Hilfe bekommt. Erstmal vielen Dank dafür!!! 👍

    Ich werde mir mal die Sache mit den Vectoren ansehen, da ich grade noch die Hälfte des Codes verstehe. 😉 Später wäre es sicherlich eh sinnvoller sowas als Objekt zu realisieren und wenn möglich zu speichern.

    Ich werd mich mal einlesen und im Zweifelsfall nochmal nachfragen. 🙂

    Danke!

    AlphaX2



  • SeppJ schrieb:

    struct PersonInfoStruct  // Ich würde bei Typennamen nicht angeben, dass es ein struct ist. Wozu soll das gut sein?
    {
      // Hier sollte man überlegen, ob die Attribute nicht lieber private sein sollten.
      std::string name;   // Vergiss char-Arrays, außer du hast einen sehr guten Grund
      std::string surname;
      float hours;
    };
    

    😕 Willst du dann für alle Member getter und setter machen, oder was hast du dir da genau vorgestellt?

    Wäre es nicht auch besser, statt float hours int minutes zu nehmen und zu Darstellungszwecken durch 60 zu teilen?


  • Mod

    out schrieb:

    😕 Willst du dann für alle Member getter und setter machen, oder was hast du dir da genau vorgestellt?

    Kommt auf die Anwendung an. Meine Klassen tun gewöhnlich etwas und sind nicht reine Datenhalden. Für reine Datenhalden bietet sich tatsächlich an, alles public zu machen. Für arbeitende Klassen 😉 sollte besser alles gekapselt sein, sonst pfuscht noch jemand von außen an den Interna herum.

    Wäre es nicht auch besser, statt float hours int minutes zu nehmen und zu Darstellungszwecken durch 60 zu teilen?

    Kommt auch auf die Anwendung an.



  • Hmm ich hab mal versucht das ganze zu verstehen, wenn ich das richtig sehe wird cin überladen und damit der Part für die Eingabe ausgelöst, oder?!

    Ist das so nötig, oder ist das nur zum verkürzen der Schreibarbeit?

    @Incocnito:
    Bei deinem Beispiel verstehe ich nicht ganz wie das mit dem vector läuft, der unter dem Namen "liste" auftaucht, dann ja aber nie genutzt wird, oder sehe ich das falsch? Du schreibst einfach in die Datei oder?

    AlphaX2



  • AlphaX2 schrieb:

    Hmm ich hab mal versucht das ganze zu verstehen, wenn ich das richtig sehe wird cin überladen und damit der Part für die Eingabe ausgelöst, oder?!

    Ist das so nötig, oder ist das nur zum verkürzen der Schreibarbeit?

    @Incocnito:
    Bei deinem Beispiel verstehe ich nicht ganz wie das mit dem vector läuft, der unter dem Namen "liste" auftaucht, dann ja aber nie genutzt wird, oder sehe ich das falsch? Du schreibst einfach in die Datei oder?

    AlphaX2

    Also erstmal wird cin nicht überladen, sondern nur der Eingabeoperator. Schau dir einfach mal "Operatorüberladung" an. Das spart in der Tat nur Schreibarbeit und sieht cooler aus. Eine Funktion ... operator >>(...) ist nur ne stinknormale Funktion wie jede andere, nur dass du halt Operatoren als Name und keine Buchtaben oder so verwendest. Kannst aber auch einfach eine Funktion void daten_einlesen(Person& p) oder sowas verwenden, wenn du das mit den Operatoren noch nicht checkst. Ist aber echt einfach.

    Und zu meinem Code: Der vector da ist tatsächlich erstmal unnötig. Ich hatte den da aber stehn, weil ich schon in Gedanken dabei war, Löschen und Ändern zu implementieren, das dann aber wohl einfach gelassen und dann vergessen hatte, die Zeile zu löschen. Ich wollte nämlich zum Löschen/Ändern aus der Datei die Personen einlesen, im vector zwischenspeichern, dann den vector bearbeiten und danach mit dem (neuen) Inhalt des vectors die Datei überschreiben.



  • Ja das meinte ich eigentlich auch, dass der Operator >> überladen wird, das Prinzip kenn ich, hab es aber tatsächlich nur 1x (in Python) genutzt. 😉
    Und in deinem Beispiel wollte ich nur sicher gehen, dass ich das richtig gecheckt hab. 😃

    Jedenfalls Danke, hab mich jetzt erst mal mit einem Minimal-Beispiel mit nur einer einfachen Zahleingabe und Zahlenliste eingefuchst. 🙂

    Danke!

    AlphaX2



  • So ich hab nochmal probiert und das ganze soweit (dachte ich), auf die Reihe bekommen, hab nun aber ein Problem mit der Ausgabe, der Code sieht jetzt so aus:

    #include <iostream>
    #include <string>
    #include <vector>
    
    struct Person
    {
        std::string name;
        std::string surname;
        float hours;
    };
    
    struct Person add_person()
    {
        Person p;
        std::cout << "Vorname: ";
        std::cin >> p.name;
    
        std::cout << "Nachname: ";
        std::cin >> p.surname;
    
        std::cout << "Stunden: ";
        std::cin >> p.hours;
    
        return p;
    }
    
    int main()
    {
        std::vector<Person> personenliste;
        Person result;
    
        do
        {
            result = add_person();
            personenliste.push_back(result);
        } while(personenliste.size() < 3);
    
        std::cout << "Dies sind die Eingaben:" << std::endl;
        int i;
        for(i=0; i<personenliste.size(); i++)
            std::cout << personenliste[i].name << std::endl;
            std::cout << personenliste[i].surname << std::endl;
            std::cout << personenliste[i].hours << std::endl;
    
        return 0;
    }
    

    Das ganze endet jedoch mit der Ausgabe der Vornamen (alle hintereinander) und anschließend mit einem Speicherzugriffsfehler. 🙄

    Leider bin ich nämlich aus der Beispiel-Ausgabe von SeppJ nicht ganz schlau geworden, also genau genommen wie die for-Schleife hier genutzt wird:

    std::cout << "Folgende Personen sind bekannt:\n";
      for (auto person : personenliste)
        std::cout << person << '\n';
    

    Vielen Dank für jeden weiteren Tipp. 😉

    AlphaX2



  • AlphaX2 schrieb:

    ...
        int i;
        for(i=0; i<personenliste.size(); i++)
            std::cout << personenliste[i].name << std::endl;
            std::cout << personenliste[i].surname << std::endl;
            std::cout << personenliste[i].hours << std::endl;
    ...
    

    Auf Anhieb fallen mir diese Zeilen schon auf.

    1. solltest du (sofern es nicht einen guten Grund gibt) die Deklaration von i auch in der Schleife machen... Dann sollte dir der 2te Fehler schon selbst auffallen.

    2. Einrückung macht noch keinen Scope. Überlege mal wozu die geschweiften Klammern auch bei Schleifen dienen.



  • * zuviel verraten *



  • AlphaX2 schrieb:

    Leider bin ich nämlich aus der Beispiel-Ausgabe von SeppJ nicht ganz schlau geworden, also genau genommen wie die for-Schleife hier genutzt wird:

    std::cout << "Folgende Personen sind bekannt:\n";
      for (auto person : personenliste)
        std::cout << person << '\n';
    

    Diese for-Schleife (ebenso wie 'auto') funktioniert nur mit C++11, und ist eine spezielle Form (In anderen Sprachen wird sie häufig foreach genannt). Der erste Ausdruck ist das Element, der zweite die Liste über die iteriert wird.



  • Okay wo ist der Facepalm Smilie 😃
    Danke! Jetzt geht es wunderbar! 🙂

    Ah okay, werd ich mal paar Infos einholen zu dem for mit auto, klingt so, als würde es ähnlich wie in Python funktionieren.

    Mal noch eine allgemeine Frage, bei dem Tutorial auf learncpp.com wird immer ein using namespace std; genutzt, hier scheint es ja die Mehrheit zu lassen und immer das std:: mit zu schreiben. Woran soll(te) man sich denn halten?

    Vielen Dank.



  • AlphaX2 schrieb:

    Ah okay, werd ich mal paar Infos einholen zu dem for mit auto, klingt so, als würde es ähnlich wie in Python funktionieren.

    Das auto hat erst einmal nichts mit diesem Schleifentyp zu tun. auto ist ein Stellvertreter für einen Typ der sich eindeutig herleiten lässt. Dient im wesentlichen der verkürzten Schreibweise:

    // Was findest du verständlicher:
    std::vector<int> intvector;
    //...
    // Alte Schleifenvariante und Iteratorverwendung ohne auto
    for(std::vector<int>::const_iterator it=intvector.begin(), end=intvector.end(); it!=end; ++it)
        cout << *it;
    
    // Alte Schleifenvariante und Iteratorverwendung mit auto
    for(auto it=intvector.begin(), end=intvector.end(); it!=end; ++it)
        cout << *it;
    

    Nachtrag:
    Die neue for-Schleife ("for each"), hat den Aufbau: "for(<Typ> <Variablenname> : <Container>)" - du bist nicht gezwungen in dieser Kombination auto zu verwenden. Aber es bietet sich hier fast an.

    AlphaX2 schrieb:

    Mal noch eine allgemeine Frage, bei dem Tutorial auf learncpp.com wird immer ein using namespace std; genutzt, hier scheint es ja die Mehrheit zu lassen und immer das std:: mit zu schreiben. Woran soll(te) man sich denn halten?

    Solange du niemals using namespace im Header, und immer hinter allen Inkludes machst, wird dir kaum einer reinreden, dann sind es persönliche Stilvorlieben. Erst wenn es zu Namenskonflikten kommt wird man dann etwas vorsichtiger.



  • AlphaX2 schrieb:

    Mal noch eine allgemeine Frage, bei dem Tutorial auf learncpp.com wird immer ein using namespace std; genutzt, hier scheint es ja die Mehrheit zu lassen und immer das std:: mit zu schreiben. Woran soll(te) man sich denn halten?

    Witzig, die Frage wiederholt sich ja.

    http://www.c-plusplus.net/forum/p2232284#2232284

    So, jetzt haben wir den Thread zweimal 😉

    Achja, das mit for(auto a : b) ist ein range-based for. Der Begriff wurde glaub ich noch nicht genannt. Einfach mal googeln.


Anmelden zum Antworten