Array erzeugt mit "new" => Realloc (Spielerei)



  • Hallo Leute,

    vorweg, ich weiß man soll das ganze eigentlich nicht machen, dafür gibt es Container. Trotzdem wollte ich es probieren.

    Also ich habe "Array-Speicher" mit 'new' angefordert. Das bisschen gefüllt.
    Dann wollte ich quasi ne Art "Realloc" durchführen. Dabei entstand dann der folgendene Code.
    Funktionieren tut es soweit, was aber bekanntlich nicht´s heißt.
    Ich bin mir nicht ganz sicher ob die Freigabe mit delete[] am Schluß so passt. (2** Pointer waren noch nie meine absolute Stärke, und ich hab auch kein Linux System zu Hand um mit Valgrind evtl. auf Speicherlöcher zu tetesn... bzw.: gibt´s da nix für Windoof? )

    main:

    #include <iostream>
    
    void show_p(int *arr, size_t size);
    int* reall(int **oldArray, int size_old, int size_new); 
    
    int main(void) {
    
    int *arr = nullptr;
    
    std::cout << "Enter 'Requested' Elements : ";
    int items;
    std::cin >> items;
    
    arr = new int[items];
    
    for (int i = 0; i < items; i++){
    
         std::cout << "Enter Value for Item Nr.: " << i << "  : " ;
    	 std::cin >> arr[i];
    }
    
    show_p(arr, items); 
    
    int neu = 5;
    
    int *myArr2 = reall(&arr, items, neu);
    
    show_p(myArr2, (items+neu));  
    
     //  delete[] arr;   // brauchen wir nicht, wurde in reall schon erledigt??
    delete[] myArr2;
    myArr2 = nullptr;
    

    reall:

    int* reall(int **oldArray, int size_old, int size_new){
    
    	int *newArray = new int[size_old+size_new]();	 
    
    	for(int i = 0; i < size_old; i++){
    
    		 *(newArray+i) = *(*oldArray)++;	// die Klammerkonstruktion wirkt bisschen "strange"?	  
    	}
    
     	delete[] *oldArray;   // *oldArray müsste richtig dereferenziert sein??  zu delete[]Kann ich das überprüfen ob erfolgreich?
     	//*oldArray = nullptr;  // ??? sollte auch richtig dereferenziert sein?
    
    	return newArray;
    }
    


  • ** ist unnötig, du gibst doch den Zeiger zurück.



  • cpp_beginner schrieb:

    (2** Pointer waren noch nie meine absolute Stärke, und ich hab auch kein Linux System zu Hand um mit Valgrind evtl. auf Speicherlöcher zu tetesn... bzw.: gibt´s da nix für Windoof? )

    Doch klar gibts da was, aber nicht so wie valgrind.

    Huch, ist schon was her, dass ich das das letzte Mal benutzt habe. Kann also grad nicht ganz garantieren, dass das so klappt:

    #include <crtdbg.h>
    
    #define _CRTDBG_MAP_ALLOC 
    
    #define new DEBUGNEW
    #ifdef _DEBUG
    
    #define DEBUGNEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
    #else  
    #define DEBUGNEW new
    #endif
    
    int main()
    {
        _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_ALWAYS_DF);
    
        // ... hier dein programm
    
        _ASSERT( _CrtCheckMemory() );
    }
    

    Edit: Nachtrag



  • cpp_beginner schrieb:

    (2** Pointer waren noch nie meine absolute Stärke, und ich hab auch kein Linux System zu Hand um mit Valgrind evtl. auf Speicherlöcher zu tetesn... bzw.: gibt´s da nix für Windoof? )

    Oder auch den Visual Leak Detector: https://vld.codeplex.com/



  • Danke erst mal für die Antworten, muss mir das mal genauer ansehen.

    Programmtechnisch:

    ** ist unnötig, du gibst doch den Zeiger zurück.

    Ja, das war eigentlich anders geplant , bzw. wird evtl. noch anders.
    Passt es soweit? Auch die "Freigabe" mit delete?



  • cpp_beginner_offl schrieb:

    Passt es soweit?

    Kommt drauf an. Legst du auf Exceptionsicherheit Wert? Dann passt der Code definitiv nicht. Mir fehlt ausserdem die Möglichkeit, Arrays mit Realloc zu verkleinern. Und zudem das mit den Zeigern auf Zeiger, was aber bereits angesprochen wurde. Wenn du wirklich das Argument verändern möchtest, dann würde sich eher eine Referenz auf einen Zeiger anbieten, das entschärft die Syntax ein wenig.

    Edit: Du kannst den Code ein wenig verschönern wenn du den Subscript-Operator ( [] ) verwendest.



  • Legst du auf Exceptionsicherheit Wert? Mir fehlt ausserdem die Möglichkeit, Arrays mit Realloc zu verkleinern

    Hier eigentich nicht, weil das nur "experimentieren" ist, und wieder ad acta gelegt wird.

    Wenn du wirklich das Argument verändern möchtest, dann würde sich eher eine Referenz auf einen Zeiger anbieten

    so:

    int* reall(int *(&oldArray), int size_old, int size_new){
    ...
          *(newArray+i) = *oldArray;    // referenz von oldArray??
          oldArray++;    // bin ich da noch richtig?
    }
    

    Und zudem das mit den Zeigern auf Zeiger, was aber bereits angesprochen wurde.

    Der Grundgedanke war das "Alte Array" zu übergeben und zu "überschreiben" , hab aber dann nicht weitergemacht, wegen unsicherheit bezgl. der **Pointer und des delete...



  • Habe jetzt folgende 2 Versionen:

    Mit Referenz:

    void reall_r(int *(&oldArray), int size_old, int size_new){
    
    	int *newArray = new int[size_old+size_new]();	 
    
    	for(int i = 0; i < size_old; i++){
    
    		 newArray[i] = *oldArray ;
    		 oldArray++;		  
    	}
    
     	delete[] oldArray;
    
     	oldArray = newArray;  		
    
    }//END reall_r
    

    Mit **pointer

    void reall(int **oldArray, int size_old, int size_new){
    
    	int *newArray = new int[size_old+size_new]();	 
    
    	for(int i = 0; i < size_old; i++){
    
    		 *(newArray+i) = *(*oldArray)++;		  
    	}
    
     	delete[] *oldArray;
    
     	*oldArray = newArray;  	
    
    }
    

  • Mod

    Eigentlich verwunderlich, dass das Programm beim delete nicht aussteigt.
    Immerhin zeigt oldArray nicht mehr auf den Anfang des alten Arrays.


  • Mod

    camper schrieb:

    Eigentlich verwunderlich, dass das Programm beim delete nicht aussteigt.
    Immerhin zeigt oldArray nicht mehr auf den Anfang des alten Arrays.

    Solange der Wert der paar Bytes die vor der Adresse auf die oldArray zeigt liegen einen sinnvoll kleinen Wert hat, sollte das doch halbwegs gut laufen? Oder terminiert die libstdc++ mit einer Assertion o.ä. wenn das Argument an delete[] nicht in irgendeiner Liste ist?



  • Ok, also beide Versionen so gesehen Schrott.
    Aber das mit den referenzen und den **pointer ist "technisch" richtig?


  • Mod

    cpp_beginner_offl schrieb:

    Aber das mit den referenzen und den **pointer ist "technisch" richtig?

    Welchen Aspekt meinst du? Wie du überhaupt so etwas wie call by reference erreichst? Ja, das hast du richtig gemacht. Aber wenn du für so etwas noch eine Bestätigung brauchst, dann ist dein derzeitiges Projekt recht ambitioniert.

    PS: Das ist kein Vorwurf. Jeder war mal Anfänger. Aber es ist ein ernstgemeinter Hinweis, dass du dich übernimmst.



  • You make my Day !!! (very relaxed Mind "exclamation marks" 😃 )

    Mir war das wichtig, weil ich es alles ausm Kopf gemacht hab, ohne Referenzen usw . Die ** Thematik ist mir lange nicht leicht gefallen, darum freut mich das jetzt schon das es "wirklich" richtig ist.

    PS: Das ist kein Vorwurf. Jeder war mal Anfänger. Aber es ist ein ernstgemeinter Hinweis, dass du dich übernimmst.

    Ich hab das schon richtig verstanden. Und du hast da schon recht.
    Ich bin c++ ganz am anfang, und bin irgendwie drauf gekommen , das mit "realloc" jetzt mal zu probieren.

    Danke an alle die sich die Zeit genommen haben , mal drüber zu sehen!

    Ps.:
    noch eine "Style" Frage:

    newArray[i] = *(oldArray++);
           vs:
    newArray[i] = *oldArray++;
           vs:
    newArray[i] = *oldArray;
      oldArray++;
    

  • Mod

    Keines davon. Viel einfacher:

    newArray[i] = oldArray[i];
    

    Dann löst sich auch von ganz alleine das Problem, auf das camper hingewiesen hat.



  • Wohl war, ginge aber auch wenn ich mir oldArray wegspeichere und dann wieder zusweise, oder statt mit oldArray mit noch nem Zeiger auf oldArray arbeite oder? (Ist jetzt schon ziemlich sinnfrei);

    "Style" technisch (ohne Funktion usw zu berücksichtigen) sagt mir

    *oldArray++

    am besten zu



  • @Skym0sh0 : Danke, werde das die Tage auf jeden Fall testen!


  • Mod

    cpp_beginner_offl schrieb:

    Wohl war, ginge aber auch wenn ich mir oldArray wegspeichere und dann wieder zusweise, oder statt mit oldArray mit noch nem Zeiger auf oldArray arbeite oder? (Ist jetzt schon ziemlich sinnfrei);

    Gehen geht viel. Ob es ein guter Weg ist, ist eine andere Frage.

    "Style" technisch (ohne Funktion usw zu berücksichtigen) sagt mir

    *oldArray++

    am besten zu

    Von den drei Varianten ist das ja auch die kürzeste, ohne unnötiges Drumherum. Man darf durchaus voraussetzen, dass ein Leser die relative Priorität von zwei häufig vorkommenden Operatoren kennt.



  • Man darf durchaus voraussetzen, dass ein Leser die relative Priorität von zwei häufig vorkommenden Operatoren kennt.

    Schon. Naja, schön wärs 🙂 Also ich hatte letztens einen Rüffler wegen fehlender Kommentare bekommen und musste dann so "nachbessern" :

    Step7:

    U #Ini_aktiv  // Abfrage ob Ini aktiv ist
    spbn _N1     // Wenn nicht gehe zu _N1
    L P##Mask_1   // Pointer auf Mask_1 laden
    LAR1   // Lade Pointer Mask_1 ins Adressregister1
    L W[Ar1, P#2.0]   // Offset 2 Wörter
    T #Status _HMI        // Zustand aus Offset in Status anzeige für Bediener laden
    
    _N1: nop 0  // Tue nichts
    

    Leider geht noch keine "Klartextprogrammierung", aber scheinbar kennen nicht alle "Code-Anseher" auch die "gängigen Code Befehle", was sich durch Kommentare nicht ändet.

    Ok, das war jetzt ziemlich off Topic


  • Mod

    cpp_beginner_offl schrieb:

    Leider geht noch keine "Klartextprogrammierung",

    Ich C++ aber schon, daher nicht vergleichbar.



  • Jetzt hat sich doch noch eine Frage, bzw. Bitte aufgetan.

    In der Variante mit der Übergabe des **Pointers habe ich folgende "Variationen" ausprobiert:

    *(newArray+i) = *(*oldArray)++;    //v1
    newArray[i] = *(*oldArray+i);     //v2 
    newArray[i] = (*oldArray)[i];    //v3
    

    Also V1 und V2 hab ich mir selbt hergeleitet wie ich da dereffernzieren muss, und ist mir auch soweit klar.
    V3 hab ich durch probieren rausbekommen. Ist mir nicht ganz so klar.
    Kann mir jmd. mit dem dereferenzieren eines **ptr, bzw. die zusammenhänge bei V3 mal etwas auf die Sprünge helfen? BTW.: Hat jmd. einen Link, Buchvorschlag oder dergleichen wo solche Sachen anschaulich erklärt werden? Gerade bei der Klammerung hau ich oft nen Hund rein.

    Meine Erklärung für mich ist bei
    V1: ich will den Wert * von dem worauf (*oldArray) zeigt zuweisen und dann das, worauf *oldArray zeigt erhöhen.

    V2: ich will den Wert * von dem worauf (*oldArray plus "Offset i" ) zeigt zuweisen usw.

    V3: ich hab solange probiert bis es kompiliert hat und nicht abstürzt.

    (*oldArray)[i]; Mir ist jetzt schon klar das ich damit auf den Wert des "alten Arrays mit dem index i " zugreife, aber ich hatte sehr sehr abenteuerliche Klammersetzungen usw. dabei.....


Anmelden zum Antworten