Namen einlesen und Speichern



  • Hallo,

    ich steh gerade bisschen auf dem Schlauch!

    Ich soll ein Programm zur verwaltung von SChülern schreiben.

    mittels eines

    struct schueler
    {
     int schueler_id;
     //char name[..];
     //char vorname[..]; // hier liegt das Problem
    }
    

    Zudem soll jede Zeichenketten nur maximal soviel Platz verbrauchen wie unbedingt nötig ist.
    Auch dürfen bibliotheksfunktionen nur für die Ein und Ausgabe benutzt werden.

    Damit das teil net immer leer ist, wollte ich schonmal von hand paar reinschreiben. Da nur die ID wichtig ist kann der Name ruhig immer Max Musterman sein oder so....

    {
     schueler *temp;
     temp=new schueler;
     temp->schueler_id=5697;
     temp->name=???
     temp->vorname=???
    }
    

    Ich schaff es nicht das irgendwie hinzubekommen das es erstmal wenigstens geht.
    Die nächste Stufe wäre dann jemanden das eingeben lassen und die Namen zu speichern

    Wäre cool wenn mir wer helfen könnte, bitte mit konkreten beispielen damit ich das auch nachvollziehen und durchprobieren könnte.

    einmal wäre es gut wenn mir wer zeigen könnte, wie ich namen unabhängig von ihrer Länge speichern kann.

    also z.b. das das dann für jeden Schueler das namensarray 20 lang ist und ich da sowohl Namen mit länbe 19 aber auch kürzere reinbekomme!

    Da das selbe, aber das der Name mittels Tastatureingabe übergeben wird.

    Und zu guter Letzt das halt jedesmal der Speicherplatz so angepasst wird, das der Name genau rein passt.

    Ich weiß ist vlt. gleich bisschen viel verlangt, aber anhand von beispielen und rumprobieren lerne ich am besten. Doch im Moment komme ich nicht weiter!



  • #include <string>
    #include <iostream>
    
    struct Schueler
    {
        std::string name;
        // more
    };
    
    int main()
    {
        Schueler sch;
        std::getline(std::cin, sch.name);
    }
    

    2 Dinge:
    - std::string in C++ nehmen für strings
    - verwende new nicht, außer es muss sein. Und dann in Kombination mit einem smart_ptr (unique_ptr) (vor C++11 auto_ptr)



  • Danke für die antwort!

    gibt es auch noch eine alternative zu deiner Lösung?
    Weil hier benötige ich ja die std. Biblio <string>!

    Die aufgabe ist aber extra so gestellt das, man halt die länge manuell anpasst!

    da:

    normal wäre ja:

    Ich mache ein Feld mit z.b. 20 Zeichen.
    Und entweder der Name passt rein = juhu aber evtl. speicherplatz verschwenung
    oder er passt nicht rein = blöd!

    und ich soll dann je nach länge der Eingabe das Feld anpassen bzw. besser gesagt den speicherplatz anpassen...



  • nachtrag:

    auch brauche ich das noch! da ich zu jedem SChüler auch noch die Fächer die er besucht speichern soll und die müsste ich dann wirklich in einem Feld speichern (zumindestens wäre es sinnvoll)

    wahrscheinlich ein FEld von zeigern das dann auf die Fächer zeigt (ist glaube ich die sinnvollste lösung)?


  • Mod

    Das scheint mir aber eine fuer deinen Wissensstand sehr schwierige Aufgabe zu sein. Im Prinzip musst du den std::string nachprogrammieren. Ist zwar fuer Fortgeschrittene denkbar einfach, aber man muss schon ein paar Sachen beachten, sonst knallt es. Hast du schon einmal von den folgenden Stichworten gehoert?
    -RAII
    -Regel der grossen Drei
    -Geometric expansion (leider weiss ich nicht, wie man das auf Deutsch nennt)

    Eventuell hast du diese Begriffe unter anderem Namen kennen gelernt, also google sie, falls du sie nicht kennt. Das solltest du wahrscheinlich sowieso tun.

    Obiges gibt dir eine Idee fuer die Strategie bei der Umsetzung, aber noch nichts ueber die technische Umsetzung in C++. Daher ein Ansatz:

    class MyString
    {
      char *begin_allocated; // Anfang eines mit new reservierten Bereichs
      char *end_allocated;   // Ende des besagten Bereichs
      char *end_string;      // Ende der Zeichenkette, die in dem bereich gespeichert ist (der Bereich kann auch groesser sein!)
    
    public:
      MyString();  // Von dir zu schreiben: Sinnvolle Startwerte festlegen
      MyString(const MyString&);  // Von dir zu schreiben: Ein neuer MyString muss sich passend speicher besorgen fuer eine Kopie
      MyString& operator=(MyString); // Von dir zu schreiben: Siehe Regel der grossen Drei / RAII
      ~MyString();  // von dir zu schreiben: Siehe Regel der grossen Drei // RAII
    };
    
    std::istream& getline(std::istream&, MyString&); // Von dir zu schreiben: Tatsaechlich etwas einlesen in den String
    
    std::ostream& operator<<(std::ostream&, const MyString&); // Von dir zu schreiben: Eine ausgabefunktion ist sicher auch ganz nuetzlich. Zusatzstichwort hier: Operatorueberladung. Kann man natuerlich auch als "normale" Funktion machen.
    

    Ganz wichtig noch: Das hat noch nichts mit dem Schueler zu tun! Der Schueler benutzt dann diesen String. Aber der String kuemmert sich um die Verwaltung der Zeichenkette, der Schueler kuemmert sich um Sachen, die mit Schuelern zu tun haben. Klare Trennung der Aufgabengebiete! Das ist eine wichtige Grundregel beim objektorientierten Programmieren.



  • Danke für die antwort, glaube so aufwendig ist die aufgabe nicht gedacht...

    in der theorie müsste es doch recht einfach sein oder nicht??

    im struct schueler ist name und vorname eine einfache Zeichenkette variabler länge bzw. ein feld was ich mit new halt zur laufzeit anfordere! und die UNterrichtsfächer ist ein Feld von Zeigern die dann jeweils auf eine zeichenkette/char Array zeigen, was jenachdem wie lang das Fach (anzahl buchstaben) dementsprechend groß ist.

    Wir haben dies in den übungen usw. hauptsächlich mit zahlen gemacht.

    ich geb hier mal ein Bsp.: an, vlt. hilft das etwas die art der aufgabenstellung zu verstehen.

    Bsp.: Feld mit int Werten, alle Werte die kleiner Null sind sollen gestrichen werden und alle positiven werte in einem neuen Feld gespeichert werden + ihre doppelten! Das Feld darf nur so groß sein wie unbedingt nötig.
    Das letzte Element im Feld hat den Wert 0!

    #include <stdio.h>
    main()
    
    {
    
      int feld[]={2,3,-1,5,-9,0};
      int length=0;
      int newlength=0;
      int pos=0;
    
        while (feld[length]!=0)
            length++;          //länge festellen
    
        for (int i=0;i<length;i++)
        {
            if (feld[i]>0)
                newlength+=2;      //länge des neuen feldes festellen
        }
        int *newArray = new int[newlength+1];  //neues feld anlegen +1 (0 am Ende)
        for (int i=0;i<length;i++)
        {
            if (feld[i]>0)
            {
                newArray[pos++]=feld[i];
                newArray[pos++]=feld[i]*2;
    
            }
        }
        newArray[pos]=0;
        return 0;
    
    }
    

    so in etwa sehen die Aufgaben aus, die wir zu diesem thema machen!


  • Mod

    Ist ja schoen*, dass ihr das so macht. Bloss ist das Problem, dass dein Programm auch prompt fehlerhaft ist und ein Speicherloch erzeugt. Eben weil die oben erwaehnten Stichworte nicht beachtet wurden und stattdessen eine Art C mit new statt malloc gemacht wurde (und selbst ein C-Programmierer wuerde sich fuer dieses Vorgehen schaemen, da er auch besser weiss, wie man solche Fehler schon beim Entwurf verhindern kann).
    Ich fuerchte, hier liegt der Fall vor, dass euer Lehrer es wohl auch nicht besser weiss.
    Im Prinzip wuerdest du - um bei diesem nicht empfehlenswerten Stil zu bleiben - genau so vorgehen wie bei deinem Beispiel mit den Zahlen. Buchstaben sind auch nur Zahlen. Womit hast du konkret Schwierigkeiten?

    *: "Schoen" sollte hier nicht woertlich genommen werden.



  • Weiß jetzt nicht was du mit SPeicherloch meinst?! Mir ist klar, das ich den neu angeforderten Speicher nach ablauf das Programs wieder freigeben muss! habe ich hier weg gelassen (wenn du das meinst...)

    Naja ich bekomme das mit Worten nicht hin! Steh da total auf den Schlauch.

    Da in meinem beispiel lege ich ja einfach ein neues Feld an und gebe das dann zurück! Würde das denn auch mit den von mir gewählten struct gehen oder wie sehe das dann aus?

    Wollte es erstmal versuchen das name/vorname eine feste länge haben:

    struct schueler
    {
      char name[20];
      char vorname[20];
    
    }
    
    main()
     {....
    
     schueler *temp;
     temp=new schueler;
     temp->name="Max";
     temp->vorname="Mustermann";
       ...
    }
    

    So in der art waren die versuche! aber dann waren entweder Fehler das der COmpiler sich am "=" stört oder er sagt char[4] nicht kompatibel mit char[20]



  • c-strings kann man nicht einfach per assignment zuweisen, bzw es ist nicht das was du denkst was es tut.

    Lösung zu dem Problem:

    #include <cstring>
    

    strcpy(ZIEL, QUELLE);
    http://www.cplusplus.com/reference/cstring/strcpy/

    hier:

    strcpy(temp->name, "Max");
    

    Anders geht es nicht, es sei denn du schreibst strcpy selbst.

    EDIT: ACHTUNG:

    To avoid overflows, the size of the array pointed by destination shall be long enough to contain the same C string as source (including the terminating null character), and should not overlap in memory with source.


Anmelden zum Antworten