Dynamisches Array



  • class liedersammlung
    {
    public:
        void neuer_eintrag(); 
        int alle_eintraege_anzeigen();
        size_t details_von_eintrag_anzeigen();
        int eintrag_bearbeiten(); 
        int eintrag_loeschen();
        int menu();
        // Daten sollten private sein!!!
    private:
        DynArray a;
    };
    

    Es ist üblich den Zugriff auf die Daten einer Klasse zu kapseln und nur über die Methoden der Klasse zu ermöglichen. Da du keinen Konstruktor deklariert hast, wird der Compiler einen Standardkonstruktor anlegen. Sobald du eine Instanz deiner Klasse erzeugst, wird damit auch ein DynArray a automatisch angelegt (innerhalb der Instanz).

    void liedersammlung::neuer_eintrag()
    {
        Lied lied1;
        cout<<"Gebe Titel, Interpret, Erscheinungsjahr, Laenge des Liedes und Genre          an!\nTitel: ";  
        cin>>lied1.titel;
        cout<<"Interpret: ";
        cin>>lied1.interpret;
        cout<<"Erscheinungsjahr: ";
        cin>>lied1.erscheinungsjahr;
        cout<<"Laenge des Liedes in der Form Minute.Sekunde: ";
        cin>>lied1.laenge;
    
        a.push_back(lied1); // a wurde vom Konstruktor erzeugt
    }
    
    void main()
    {
        liedersammlung lieder; // Aufruf des Standardkonstruktors von liedersammlung
    
        lieder.neuer_eintrag(); // Lied hinzufügen
    }
    

    Edit: Ich hatte was überlesen 😞



  • Hmm ok aber das bringt mir jetzt auch nicht so wirklich weiter glaub ich.

    Mein problem ist ja mittlerweile das wenn ich z.b. den Kontruktor

    DynArray::DynArray(int newCapacity)
    {
        m_data = new Lied[newCapacity];
        m_data_anfang = m_data;
        m_capacity = newCapacity;
        m_size=0;
    }
    

    in main mit

    DynArray a(5);
    

    aufrufe und dann ein Objekt Lied erstelle und irgendwas reinschreibe

    Lied lied1;
        lied1.titel="test";
        lied1.interpret="interpret";
        lied1.erscheinungsjahr=3849;
        lied1.laenge=5.3;
    

    Und dann steck ich das lied1 in meine push_back funktion rein

    void DynArray::push_back(Lied elem)
    {
        m_size+=1;
        if(m_size == m_capacity)
        {
            resize(2*capacity());
            *m_data=elem;
        }
        else 
            *m_data=elem;
        m_data+=1;          // m_data auf den nächsten index zeigen lassen
    }
    

    Und dann schreib ich in main

    cout<<a.m_data->titel;
    

    Was natürlich nichts ausgibt, weil ich in der push_back-Funktion nicht das m_data der Instanz 'a' verändert habe. Es würde funktionieren wenn ich von der Instanz a in der main das

    a.m_data
    

    als Zeiger dem push_back übergebe und der hantiert dann mit dem a.m_data herum. Aber das ist denke ich nicht Sinn der sache.

    Ich hab mal etwas gesucht und es gibt vllt irgendwie die Möglichkeit alle Dyn-Array variablen als static zu machen, was die wohl dann irgendwie global machen, aber das ist denke auch nicht gut.

    mein kernproblem ist nun einfach das ich es nicht hinkrieg das meine DynArray-funktionen wie z.b. das push_back oder auch der konstruktor mit den Variablen aus z.b. einer Instanz die ich in main aufrufe hantieren zu lassen.



  • Du brauchst kein DynArray in main.



  • Na, aber irgendwo muss ich ja ein dynarray anlegen.

    aber ich gebs jetzt auch auf. Geht vllt. einfach nicht mit den Sachen die ich bis jetzt kann. drecks aufgabe, schmorr in der hölle.



  • vivess schrieb:

    Na, aber irgendwo muss ich ja ein dynarray anlegen.

    Ja, in Liedersammlung

    aber ich gebs jetzt auch auf. Geht vllt. einfach nicht mit den Sachen die ich bis jetzt kann. drecks aufgabe, schmorr in der hölle.

    Du hast etwas grundlegendes nicht verstanden. Das hat nichts mit dieser Aufgabe zu tun. Solange du das nicht verstehst wirst du ziemlich Probleme mit deinen weiteren Aufgaben haben.



  • aber in den folien steht auch ein feuchter dreck dazu. kann ja nicht sein das ich mir da alles selber ausm Hintern ziehen muss.



  • Was unterscheidet Dynarray von std::string?
    Was unterscheidet "Titel" von "Array von Liedern"?

    Wenn du Titel nicht in main erzeugen musst, warum dann das Array?



  • das war ja nur ein beispiel um mein problem darzustellen. selbst wenn ich dynarray in liedersammlung erzeuge hilft mir das genau GAR NICHTS.



  • vivess schrieb:

    das war ja nur ein beispiel um mein problem darzustellen. selbst wenn ich dynarray in liedersammlung erzeuge hilft mir das genau GAR NICHTS.

    Doch, hilft.

    Mal ein Beispiel:

    class Foo
    {
        public:
            void setIntValue(int i); // öffentliche Methonde, um den privaten Wert zu ändern
            int getIntValue(); // öffentliche Methode, um den privaten Wert abzurufen
        private:
            int theValue; // der privat gespeicherte Wert
    }
    
    void Foo::setIntValue(int i)
    {
        theValue = i;
    }
    
    int Foo::getIntValue()
    {
        return theValue;
    }
    
    void main()
    {
        Foo foo; // Erzeugt eine Instanz von Foo. Der vom Compiler automatisch erstellte
                 // Konstruktor wird nun alle intern benötigten Variablen erzeugen.
                 // In diesem Fall wurde "theValue" erzeugt.
        foo.setIntValue(10); // weißt dem privaten theValue einen Wert zu
    
        int aValue = foo.getIntValue(); // ruft diesen Wert wieder ab.
    }
    

    Wenn du keinen Konstruktor für deine Klasse vorgibst, dann wird vom Compiler einer automatisch erzeugt und dieser kümmert sich erst mal um alles nötige. Siehst du oben in "main" irgendwo, dass "theValue" explizit erzeugt wurde?

    Möglicherweise habe ich aber auch dein Problem nicht verstanden...

    Edit:

    Vielleicht haben wir dich allerdings auch unnötig verwirrt. Für die Aufgabe würde es tatsächlich reichen zwei Klassen zu erstellen. Eine Klasse "Lied" und eine Klasse "DynArray" (das Lieder aufnehmen kann). Dann würde es in der main ungefähr so aussehen (Pseudocode):

    DynArray liedersammlung{10}; dynamisches Array für 10 Lieder
    
    Lied lied;
    lied.titel = "Blah...";
    //usw.
    
    liedersammlung.push_back(lied);
    

    Allerdings hat "Neuer Eintrag" nichts in der Klasse Lied zu suchen. Ist ja logisch. Die Klasse Lied weiß ja nichts von dem Array, wie soll es sich also irgendwo neu eintragen können?



  • vivess schrieb:

    in main mit

    DynArray a(5);
    

    aufrufe und dann ein Objekt Lied erstelle und irgendwas reinschreibe

    Und dann steck ich das lied1 in meine push_back funktion rein

    Und dann schreib ich in main

    cout<<a.m_data->titel;
    

    Was natürlich nichts ausgibt, weil ich in der push_back-Funktion nicht das m_data der Instanz 'a' verändert habe. Es würde funktionieren wenn ich von der

    Wenn du

    a.push_back(...)
    

    dann wird natürlich auch "m_data" der Instanz "a" verwendet. Das ist ja der Sinn davon, die Daten gehören zur jeweilingen Instanz der Klasse.

    DynArray a(5);
    DynArray b(5);
    
    a.push_back(...); // verwendet das interne m_data von a
    b.push_back(...); // verwendet das interne m_data von b
    


  • vivess schrieb:

    2.3.5 void resize(int newCapacity)
    Ein Aufruf von resize vergrößert das Array eines DynArray-Objekts. Diese Funktion wird nur intern verwendet und ist
    daher private. Um ein bestehendes Array zu vergrößern m¸ssen Sie folgende Schritte durchführen:
    1. Erzeugen eines neuen dynamischen Arrays der Größe newCapacity
    2. Kopieren der Daten aus dem bestehenden Array in das neu erzeugte
    3. Löschen des bestehenden Arrays
    4. Den m_data-Zeiger auf das neu erzeugte Array setzen

    Ich versteh aber nicht wie ich das machen soll. Meine DynArray(int new Capacity) funktion sieht so aus:

    DynArray::DynArray(int newCapacity)
    {
        m_data = new Lied[newCapacity];
        m_capacity = newCapacity;
        m_size=0;
    }
    

    Aber wenn ich wie in der aufgabenstellung für das resize im Schritt 1 ein neues array anlege, wird ja der zeiger m_data direkt auf das neue array gerichtet, aber im 4. Schritt steht dann auf einmal ich soll den m_data zeiger auf das neu erstellte array richten, aber das mach ich doch schon sofort?

    Was ist mit Schritt 2? Um etwas kopieren zu können, muss zumindest bis die Kopie erstellt ist noch das Original vorhanden sein (m_data darf also nicht sofort neu zugewiesen werden, sonst ist es weg). Du musst genau das tun, was oben in den Schritten 1 - 3 beschrieben ist. "Resize" wird demnach so ähnlich arbeiten wie der Konstruktor, aber mit ein paar zusätzlichen Schritten.

    Außerdem noch:

    cout<<a.m_data->titel;
    

    Wenn a ein Array ist dann fehlt beim Zugriff auf die Daten irgendwie noch die Angabe eines Indexes. Woher soll dein Array wissen, welches Lied du genau haben möchtest, z.B.

    cout<<a.getLied(0)->titel;
    

    Ich lerne ja auch gerade C++ und wenn ich Probleme an einer Stelle habe, dann versuche ich erst mal mit einem vereinfachten Beispiel das Problem zu lösen. Anschließend erweitere ich die Lösung auf das ursprüngliche Problem.

    Bastel dir doch erst mal ein dynamisches Array für einfache Datentypen:

    class IntArray
    {
        public:
            IntArray(int capacity);
            ~IntArray(); // destructor nicht vergessen, um das interne array wieder freizugeben!
            void pushBack(int value);
            int get(int index);
        private:
            int* array = nullptr;
            int size = 0;
            int capacity = 0;
            void resize(int newCapacity);
    };
    

    Wenn das funktioniert:

    int main(int argc, char *argv[])
    {
        IntArray ints(10); // startgröße 10
    
        for (int i = 1; i <= 100; i++) // 100 werte einfügen
        {
            ints.pushBack(i);
        }
    
        std::cout << "the answer to all: " << ints.get(41) << std::endl; // ganz wichtig ;)
        return 0;
    }
    

    dann kannst du den Datentypen ja auf Lieder ändern.

    Schau dir auch im Debugger Schritt für Schritt an, was dein Programm macht oder lass dir zur Kontrolle in den einzelnen Methoden etwas auf die Konsole ausgeben:

    void IntArray::pushBack(int value)
    {
        std::cout << "pushBack begin, capacity: " << capacity << " size: " << size << std::endl;
        if (capacity <= size)
        {
            resize(capacity + 10); // resize array +10
        }
    
        array[size++] = value;
    
        std::cout << "pushBack done, capacity: " << capacity << " size: " << size << std::endl;
    }
    

    ...
    pushBack begin, capacity: 10 size: 8
    pushBack done, capacity: 10 size: 9
    pushBack begin, capacity: 10 size: 9
    pushBack done, capacity: 10 size: 10
    pushBack begin, capacity: 10 size: 10
    resize done, capacity: 20 size: 10
    pushBack done, capacity: 20 size: 11
    pushBack begin, capacity: 20 size: 11
    pushBack done, capacity: 20 size: 12
    pushBack begin, capacity: 20 size: 12
    pushBack done, capacity: 20 size: 13
    pushBack begin, capacity: 20 size: 13
    pushBack done, capacity: 20 size: 14
    ...


Anmelden zum Antworten