Ein Array nachträglich vergrößern



  • 1.Kann mir jemand sagen wie ich am besten nachträglich ein Array vergrößere. Damit meine ich dass der Benutzer die Array größe bestimmt (also ist noch nicht zur Laufzeit bekannt), und dann nachträglich nochmal vergrößern kann. Ich hab das mal umgesetzt, wie man bei dem "Test" sehen kann funktioniert es nicht, bzw nicht immer, manchmal kommt was manchmal auch nicht. Das blick ich überhaupt nicht! Ich glaub das liegt irgendwie an den Zahlen die der Benutzer eingibt, mh bin grad bissel verwirrt. Was mach ich falsch?

    2.Geht das auch irgendwie mit weniger Code einfacher etc.. weil ich weiß nicht ob die Funktion "FromArrayToNewArray" zu umständlich ist. Wie würdet den ihr das machen?

    Hier mal der Code:

    #include <iostream>
    using namespace std;
    
    class Mitarbeiter
    {
        public:
        Mitarbeiter();
        ~Mitarbeiter();
        void SetGehalt(int a) {Gehalt=a;}
        void SetAlter(int a) {Alter=a;}
        void SetName(string a) {Name=a;}
        int GetGehalt(){return Gehalt;}
        int GetAlter() {return Alter;}
        string GetName() {return Name;}
    
        private:
        int Gehalt;
        int Alter;
        string Name;
    };
    void FromArrayToNewArray(Mitarbeiter *Firma,int OldArrayEnd,int NewArrayEnd);
    Mitarbeiter::Mitarbeiter()
    {
    
    }
    
    Mitarbeiter::~Mitarbeiter()
    {
    
    }
    
    int main()
    {
    
        int BenEing1;
        int BenEing2;
        cout << "Wieviele Mitarbeiter sollen Angestellt werden?\n";
        cin >> BenEing1;
        Mitarbeiter *Firma=new Mitarbeiter[BenEing1];
        for (int i=0;i<BenEing1;i++)
        {
            Firma[i].SetGehalt(i+(i*80)+200);
        }
        cout << "Wieviele neue Mitarbeiter?\n";
        cin >> BenEing2;
        FromArrayToNewArray(Firma,BenEing1,BenEing2);
    
        //#TEST# (Testen obs geklappt hat)
        for (int i=0;i<BenEing1;i++)
        {
            cout << Firma[i].GetGehalt() << endl;
        }
    
        return 0;
    }
    
    void FromArrayToNewArray(Mitarbeiter *Firma,int OldArrayEnd,int NewArrayEnd)
    {
        Mitarbeiter *temp=new Mitarbeiter[OldArrayEnd];
        for (int i=0;i<OldArrayEnd;i++)
        {
            temp[i]=Firma[i];
        }
        delete Firma;
        Firma=NULL;
        Firma=new Mitarbeiter[NewArrayEnd];
        for (int i=0;i<OldArrayEnd;i++)
        {
            Firma[i]=temp[i];
        }
    }
    

    Wo ist der Fehler?
    Dankeschön schon mal im Voraus.



  • Hallo

    Stromberg schrieb:

    Damit meine ich dass der Benutzer die Array größe bestimmt (also ist noch nicht zur Laufzeit bekannt), und dann nachträglich nochmal vergrößern kann.

    Du meinst statt Laufzeit bestimmt Compilezeit, weil du das Array ja gerade während der Laufzeit ändern willst. das geht ganz einfach und zwar mit std::vector. Da kannst du mittel push_back() jederzeit neue Daten reinschieben. Sehr praktisch und leicht zu handhaben.

    chrische



  • Habs jetzt nicht im Detail durchgekuckt, aber da du ja den Zeiger verändert willst solltest Du den pointer per Referenz übergeben.

    void FromArrayToNewArray(Mitarbeiter *& Firma,int OldArrayEnd,int NewArrayEnd)
    

    Generell solltest Du die stl benutzen. Also std::vector std::copy usw.



  • mh
    zum "mal gehts mal gehts nicht" bei der ausgabe geht deine schleife nur bis zum ende des ersten array, dein array scheint aber eine neue länge nämlich BenEing2 zu haben und nicht BenEing11!
    Ausserdem weis ich nicht wirklich was passieren soll wenn BenEing2 kleiner als BenEing1 ist, dann kopierst du bei deiner arrayfunktion angenommen BenEing1 = 10 Member in ein Array von BenEing2 = 1 großes Array das kann nur schief gehn, ausser du willst mit "wieviele neue" wirklich neue addieren!!!

    SO erstmal das!

    zum "obs einfacher geht" und dem mit den "neuen mitarbeitern"

    void FromArrayToNewArray(Mitarbeiter *Firma,int OldListSize,int NewMember)
    {
        Mitarbeiter *temp=new Mitarbeiter[OldListSize+NewMember];
        memset(temp, 0, sizeof(Mitarbeiter)*(OldListSize+NewMember)); // initialisieren
        memcpy(temp, Firma, sizeof(Mitarbeiter)*OldListSize); // kopieren
        delete[] Firma; // altes Array löschen
        Firma = temp; // Pointer neue Liste übergeben
    }
    

    Die kopierliste kannst du dir getrost sparen, zeigt der pointer zwischen delete und der zuweisung auch mal ins leere macht das doch sicher kein problem bei deiner anwendung oder ?

    erm da muss ich zustimmen, isses keine schulaufgabe benutz lieber vector<Mitarbeiter> MitarbeiterListTyp;
    MitarbeiterListTyp MitarbeiterListe;

    mit push, at(index) und delete(index) (geht da nich eigentlich auch ne list<Mitarbeiter> dächte das wäre einfacher)

    MEGAEDIT wenn du schon Arrays löschst, bitte mit dem richtiggen delete[] und nicht dem einfachn delete



  • Servus,

    will hier eben nur kurz auf die vielleicht hilfreichen Artikel im Magazin hinweisen.

    Hier die Direktlinks zu CStolls Artikeln:
    Aufbau der STL - Teil 1: Container
    Aufbau der STL - Teil 2: Iteratoren und Algorithmen
    Aufbau der STL - Teil 3: Hilfsklassen und Erweiterungen

    Jedoch finde ich die Übung ganz gut und würd dir empfehlen noch ein wenig damit "rumzuspielen". Wenn du dann denkst deine Methode ist ausgereift, dann schau dir die entsprechende in der stl an und du wirst das eine oder andere "Aha-Erlebniss" haben 🙂

    Gruß von der alt-neuen Baracke



  • bedenke das das da oben verdammt nach schulaufgabe klingt und bedenke nun das die meistens vector nich benutzen dürfen wenns nich ausdrücklich verlangt wird, oder der lehrer zu dämlich ist XD



  • Servus,

    hehe, gut möglich aber das ändert nichts an dem was ich geschrieben habe. Es geht mir am Ende vom letzten Post nicht darum das er die STL verwendet. Zugegeben sie erleichtert das Programmieren enorm dadurch das sie den den Code protabler macht, ist mehrfach getestet, es gib gut Dokumentationen usw... doch das ist alles für die Katz wenn er nicht weiss was er macht.
    Und genau dafür finde ich diese Übung gut, wenns für eine Schulaufgabe ist um so besser. Dann kann er den Lehrer ein wenig nerven ob er die STL oder Templates einsetzten darf. Falls er sich dann quer stellt kann er die meist mehrdeutigen Aufgaben in Frage stellen......
    Das war eine der wenigen Sachen die ich ganz amüsant am Unterricht fand 😉

    Die Schule von einer Baracke



  • AHH der Haupfehler lag wo daran das es nicht "Mitarbeiter *&Firma" ist. wie templäd gesagt hat, doch um die Situation jetzt noch n bissel schwieriger zu machen fänd ich toll alles mit Zeigern zu machen 🙂
    Hab mal was gehört das man auch Zeiger auf Zeiger machen darf also **Z oder so?

    #include <iostream>
    using namespace std;
    
    class Mitarbeiter
    {
        public:
        Mitarbeiter();
        ~Mitarbeiter();
        void SetGehalt(int a) {Gehalt=a;}
        void SetAlter(int a) {Alter=a;}
        void SetName(string a) {Name=a;}
        int GetGehalt(){return Gehalt;}
        int GetAlter() {return Alter;}
        string GetName() {return Name;}
    
        private:
        int Gehalt;
        int Alter;
        string Name;
    };
    void FromArrayToNewArray(Mitarbeiter *Firma,int OldArrayEnd,int NewArrayEnd);
    Mitarbeiter::Mitarbeiter()
    {
    
    }
    
    Mitarbeiter::~Mitarbeiter()
    {
    
    }
    
    int main()
    {
    
        int BenEing1;
        int BenEing2;
        cout << "Wieviele Mitarbeiter sollen Angestellt werden?\n";
        cin >> BenEing1;
        Mitarbeiter *Firma=new Mitarbeiter[BenEing1];
        cout << &Firma << " " << Firma << endl;
        for (int i=0;i<BenEing1;i++)
        {
            Firma[i].SetGehalt(i+(i*80)+200);
        }
        cout << "Wieviele neue Mitarbeiter?\n";
        cin >> BenEing2;
        FromArrayToNewArray(Firma,BenEing1,BenEing2);
    
        //Testen obs geklappt hat
        cout << "TEST\n";
        for (int i=0;i<BenEing1;i++)
        {
            cout << Firma[i].GetGehalt() << endl;
        }
    
        return 0;
    }
    
    void FromArrayToNewArray(Mitarbeiter **Firma,int OldArrayEnd,int NewArrayEnd)
    {
        Mitarbeiter *temp=new Mitarbeiter[OldArrayEnd];
        for (int i=0;i<OldArrayEnd;i++)
        {
            temp[i]=*Firma[i];
        }
        delete []*Firma;
        *Firma=NULL;
        *Firma=new Mitarbeiter[NewArrayEnd];
        for (int i=0;i<OldArrayEnd;i++)
        {
            *Firma[i]=temp[i];
        }
    }
    

    Hätte das dann irgendwie so gemacht,aber umso länger ich esmir anchaue desto konfuser wird es! Außerdem läuftsnicht siehe hier:
    Compiling: C:\MinGW\Andi\mitarbeiter.cpp
    Linking console executable: C:\MinGW\Andi\mitarbeiter.exe
    C:\MinGW\Andi\mitarbeiter.o:mitarbeiter.cpp:(.text+0x3aa): undefined reference to `FromArrayToNewArray(Mitarbeiter*, int, int)'
    collect2: ld returned 1 exit status
    Process terminated with status 1 (0 minutes, 0 seconds)
    0 errors, 0 warnings

    Hoffe das ihr mir wieder weiterhelfen könnt.

    PS: Sry das ich erst so spät zurückschreibe (musst lööörnen), äh und das ganze hier hat eientlich nichts mit einer Schulaufgabe zu tun.



  • Stromberg schrieb:

    1.Kann mir jemand sagen wie ich am besten nachträglich ein Array vergrößere. Damit meine ich dass der Benutzer die Array größe bestimmt (also ist noch nicht zur Laufzeit bekannt), und dann nachträglich nochmal vergrößern kann. Ich hab das mal umgesetzt, wie man bei dem "Test" sehen kann funktioniert es nicht, bzw nicht immer, manchmal kommt was manchmal auch nicht. Das blick ich überhaupt nicht! Ich glaub das liegt irgendwie an den Zahlen die der Benutzer eingibt, mh bin grad bissel verwirrt. Was mach ich falsch?

    2.Geht das auch irgendwie mit weniger Code einfacher etc.. weil ich weiß nicht ob die Funktion "FromArrayToNewArray" zu umständlich ist. Wie würdet den ihr das machen?

    erzeuge doch einfach ein Array aufem heap. das array kannst du dann während der laufzeit des programms bzw bei der erschaffung vergrößern.

    char *z = new char[länge]
    

    das is jetzt nur ein beipiel wie es geht.
    z wird dann als zeiger auf ein Array auf dem Heap erschaffen. da das auf dem heap ist,so kannst du zb die größe im vorherigem code durch eine benutzereingabe auswählen.
    ob man es auch nach der erschaffung verändern kann denke ich nicht da das ja eigentlich zum absturz führen kann.



  • Also würde ich C++ programmieren, würde ich jeden Tag feiern, dass es std::vector gibt 😉



  • iss doch klar, in der cpp verwendest du Firma** in der header nur Mitarbeiter* , Firma** == Mitarbeiter***

    args .... mir dreht sich alles

    versuchs doch bitte mit
    void bla(Mitarbeiter* &Firma, int, int);

    dann sollte meine variante auch endlich funktionieren XD

    und nenn es doch innerhalb der funtion nich wie in der main "Firma" sondern FirmaPtr oder so ...

    pointer auf pointer kannst du gern versuchen aber das endet nur in verwirrung

    belass es bei call by reference auf nen Mitarbeiter-pointer



  • in der cpp verwendest du Firma** in der header nur Mitarbeiter* , Firma** == Mitarbeiter***

    Hä das blick ich net? Ich hab doch gar keine header dabei, kannst mir das nochmal genau erklären? Dankeschön schon mal im Voraus.



  • ja sorry war schon spät hab den ganzen tag wieder quelltext auseinandergefriemelt und bissl stresst gehabt dein quelltext richtig zu lesen XD

    nien sorry so ad hoc fällt mir der fehler nciht auf ..... wuaaah schon so spät ? -.- und morgen wieder auf arbeit



  • ganz einfach, ein Array ist ein Stapel.
    Im Idealfall sieht das als Code näherungsweise so aus:

    template <typename T> class Array{
    protected:
    T* Element;
    unsigned amountOf;
    unsigned allocatedMemory; // soll regulieren, wann wieder einmal Speicher
     // allokiert werden muss
    public:
    Array(); // Sollte alles ausnullen, weil möglicherweise auch gar keine Elemente
     // in das Array geschrieben werden, also auch Element = NULL;
    
    ~Array(); // Sollte für einen sauberen Abgang sorgen
    
    T& operator[](unsigned index); /* Soll dem Anwender der Klasse den Zugriff auf 
      die Arrayelemente in gewohnter [] Syntax erlauben, und falls der Index zu groß
      ist, sorgt die Funktion natürlich dafür (mittels new), das Array notfalls
      soweit zu vergrößern, dass der Index passt */
    
    bool insert(const T& Eingefuegt); // Arbeitet ähnlich wie [], gibt dem Anwender
     // allerdings die Sicherheit, dass ein Element auch garantiert am Ende des
     // Arrays eingefügt wird
    
    bool drop(const T& Verworfen); /* Und diese Funktion sorgt letztlich dafür,
      dass das erstbeste Element, das identisch zu Verworfen ist, gelöscht wird.
      Alle 'Bausteine' des Stapels droppen dann natürlich um eins nach 'unten' */
    };
    
    /* Dieses Tolle Array kann dann überall so erzeugt werden (beispielsweise wenn man D3DMATERIAL9 Strukturen darin speichern möchte, oder auch nur einfache int)*/
    
    int WINAPI WinMain(HINSTANCE hinst, HINSTANCE phinst, LPSTR commandLine,
     int ShowStyle){
    // fuer int sieht's so aus:
    Array<int> Zahlenliste; // sofern sich operator[] und insert darum kümmern,
      // dass das Array dynamisch erweitert wird, hat man jetzt die Narrenfreiheit,
      // an einem beliebigen Array-Index einen beliebigen int Wert zu speichern
    
    // für D3DMATERIAL9 funktioniert das gleiche Array!
    Array<D3DMATERIAL9> Materials; // egal wie komplex der Datentyp auch sein mag,
     // dieses Tolle Array kann sie speichern!
     // Und die einzelnen Elemente werden dank des überladenen [] Operators in der
     // gewohnten Array-Syntax erreicht, also beispielsweise so:
    
    Zahlenliste[5]=3;
    
    return 0;
    };
    

    Damit das Array auch brav dynamisch wächst, wenn der Benutzer des Arrays einen zu großen Index angeben sollte, erzeugt man erst einen temporären T* Zeiger,
    weist dann diesem Zeiger mittels new den seit neuestem benötigten Speicherbereich mittels new zu, kopiert dann die alten Elemente aus T* Element in diesen temporären T* Zeiger, löscht dann den alten Elemente-Zeiger, setzt ihn dann gleich mit dem temporären T* Zeiger, und kopiert im Falle von insert() den Inhalt des einzufügenden neuen Elements ans Ende der Liste. Im Falle der Funktion operator[] gibt man dann einfach Element[index] zurück. Das allerdings zufälligen Inhalt haben kann, weil der Anwender des Arrays/Stapels den Indexbereich überschritten hat. Kommt auch auf die Konstruktoren von T an.
    Im Normalfall wird der Anwender aber den Index immer nur dann überschreiten, wenn er etwas in das Element-Array kopieren möchte, und noch nicht weiß, wieviele Elemente das Array einmal haben wird.

    Dieses Array ist insofern einfach zu handhaben, als dass die gewohnte Array-Syntax nicht verloren geht. Und viel öfter benötigt man Stapel als Listen. Leider kommt man auch nie darum herum, Stapel-Klassen selbst zu schreiben, weil <vector> seine Elemente irgendwo verstreut im Speicher ablegt, und man aber leider oft darauf angewiesen ist, dass Elemente auch wirklich garantiert hintereinander im Speicher abgelegt werden, und nicht irgendwo in der Wildnis.

    Viel Spass mit dieser Stapel/Array-Klasse!

    Hehe



  • Mh ja ich verstehst so halb, muss es mir noch paar mal genau durchlesen, was ich aber gar net verstehe, warum braucht man da nen WinAPI Kopf? Also mit WinAPI kenn ich mich ja gar net aus, also sollte der Kopf nötig sein dann is es keine alternative für mich.



  • Stromberg schrieb:

    Mh ja ich verstehst so halb, muss es mir noch paar mal genau durchlesen, was ich aber gar net verstehe, warum braucht man da nen WinAPI Kopf? Also mit WinAPI kenn ich mich ja gar net aus, also sollte der Kopf nötig sein dann is es keine alternative für mich.

    Nein, der ist nicht nötig - natürlich kannst du solche Arrays auch in einer "normalen" main()-Funktion anlegen.

    (@EinigesIntus: Warum selber schreiben? Nimm doch gleich std::vector<>)



  • JUHUH 😃 !!! So ich glaub es geht jetzt. Hab doch n paar Fehler gefunden und hab das so wie ichs mir gedacht hab ganz ohne Referenzen, sondern nur mit Zeigern gemacht. 😃 Hier wär dann mal der Code, vll. interessierts ja jemand, meiner Meinung nach funktionierts, würd mich aber über Verbeserungsvorschläge etc... freuen! 🙂

    #include <iostream>
    using namespace std;
    
    class Mitarbeiter
    {
        public:
        Mitarbeiter();
        ~Mitarbeiter();
        void SetGehalt(int a) {Gehalt=a;}
        void SetAlter(int a) {Alter=a;}
        void SetName(string a) {Name=a;}
        int GetGehalt(){return Gehalt;}
        int GetAlter() {return Alter;}
        string GetName() {return Name;}
    
        private:
        int Gehalt;
        int Alter;
        string Name;
    };
    void FromArrayToNewArray(Mitarbeiter **Firma,int OldArrayEnd,int NewArrayEnd);
    Mitarbeiter::Mitarbeiter()
    {
    
    }
    
    Mitarbeiter::~Mitarbeiter()
    {
    
    }
    
    int main()
    {
    
        int BenEing1;
        int BenEing2;
        cout << "Wieviele Mitarbeiter sollen Angestellt werden?\n";
        cin >> BenEing1;
        Mitarbeiter *Firma=new Mitarbeiter[BenEing1];
        for (int i=0;i<BenEing1;i++)
        {
            Firma[i].SetGehalt(i+(i*80)+200);
        }
        cout << "Wieviele neue Mitarbeiter?\n";
        cin >> BenEing2;
        FromArrayToNewArray(&Firma,BenEing1,BenEing2);
    
        //#TEST# (Testen obs geklappt hat)
        for (int i=0;i<BenEing1;i++)
        {
            cout << Firma[i].GetGehalt() << endl;
        }
    
        return 0;
    }
    
    void FromArrayToNewArray(Mitarbeiter **ArrayTemp,int OldArrayEnd,int NewArrayEnd) //hier war der Funktionsparameter
                                           //(der vorher "*Firma" hieß) falsch, da ich so nicht den Zeiger Firma aus Zeile
                                           //39 angesprochen habe, sondern nur immer die Adress des ersten Elements.
    {
        Mitarbeiter *temp=new Mitarbeiter[OldArrayEnd];
        for (int i=0;i<OldArrayEnd;i++)
        {
            temp[i]=(*ArrayTemp)[i];
        }
        delete []*ArrayTemp; //EDIT: äh ich glaub das muss doch [](*ArrayTemp) heißen? (siehe diesen Beitrag bei dem ich das gefragt               
    //habe: http://www.c-plusplus.net/forum/viewtopic-var-t-is-172525.html ) 
        *ArrayTemp=NULL;
        *ArrayTemp=new Mitarbeiter[OldArrayEnd+NewArrayEnd]; // hier warn Fehler da BinEing2 (Zeile 46) nur angibt um wieviel
                                                             // größer das Array werden soll.
        for (int i=0;i<OldArrayEnd;i++)
        {
            (*ArrayTemp)[i]=temp[i];
        }
        delete []temp;
    }
    

    @CStoll ja okay es ist sicherlich einfacher "std::vector" zu nehmen, war aber jetzt halt eher so nä kleine "Herausforderung" an mich, das zu schreiben. Und man freut sich danach richtig wenns endlich funktioniert (also äh müsst jetzt glaub schon gehen).
    Und ich hab auch wieder einiges gelernt dabei!

    Dankeschön schon mal im Voraus.


Log in to reply