Frage zu Malloc und Free



  • Hallo,

    ich habe keine Frage zu malloc() und free().
    Wenn ich es richtig verstanden habe kann ich mit malloc() ein Speicher auf dem Heap reservieren bzw. beanspruchen und mit free() wieder frei geben.

    Ich habe nun folgende Funktion gegeben:

    void f(){
    int x = 0;
    }
    

    mit der folgenden Aufgabe:
    Ergänzen Sie nun die Funktion f() um zwei lokale Variablen px und ppx und initialisieren Sie diese mit zwei Adressen, welche Speicher- bereiche auf dem Heap bezeichnen: px soll dabei auf einen Speicherbe- reich zeigen, in dem ein ganzzahliger Wert gespeichert werden kann und ppx soll auf einen Speicherbereich zeigen, in dem die Adresse einer ganzzahligen Variablen gespeichert werden kann. Initialisieren Sie den Inhalt der ersten Variable auf dem Heap mit dem Wert von x und den Inhalt der zweiten Variable auf dem Heap mit der Adresse der ersten Variablen auf dem Heap. Geben Sie wiederum die Werte und die Adres- sen der Variablen x, px und ppx auf der Konsole aus und geben Sie den dynamisch angeforderten Speicher wieder frei. Die Ausgabe sollte dann etwa wie folgt aussehen:
    x = 0 Adresse von x: 0x7ffc654c45dc
    px = 0x7ffc654c45dc Adresse von px: 0x7ffc654c45e0
    ppx = 0x7ffc654c45e0 Adresse von ppx: 0x7ffc654c45e8

    Ich habe folgendes bis jetzt programmiert:

    void f(){
      int x = 0;
      int *px;
      int *ppx;
    
      px =  malloc(sizeof(int));
      ppx = malloc(sizeof(int *));
    
      px = &x;
      ppx = &px; 
    
      printf("x: %d\t Addr: %d\n", x, &x);
      printf("px: %d\t Addr: %d\n", px, &px);
      printf("pxx: %d\t Addr: %d\n", ppx, &ppx); 
    }
    

    Meine Fragen:
    -Hab ich es bis jetzt richtig gelöst?
    -Warum kann ich den Speicher nicht wieder freigeben?

    Wenn ich free(px) oder free(ppx)aufrufe bekömmlich folgende Fehlermeldung:
    a4(64569,0x7fffda43d3c0) malloc: *** error for object 0x7fff59a97900: pointer being freed was not allocated
    *** set a breakpoint in malloc_error_break to debug

    Hoffe auf Hilfe, danke im Voraus!

    Lg



  • Momolo schrieb:

    ich habe keine Frage zu malloc() und free().

    Sondern? 🙂

    Initialisieren tut man direkt bei der Definition der Variablen. Einen Zeiger kann man noch gerade so mit einer Adresse auf dem Heap initialisieren:

    int *px = malloc(sizeof(int));
    int **ppx = malloc(sizeof(int *));
    

    , aber den Wert dahinter kriegt man nur zugewiesen. Initialisierung != erste Zuweisung.

    Das hier:

    Momolo schrieb:

    ppx soll auf einen Speicherbereich zeigen, in dem die Adresse einer ganzzahligen Variablen gespeichert werden kann

    hast du ebenfalls falsch verstanden. ppx soll ein Zeiger auf einen Zeiger auf einen ganzzahligen Wert sein, nicht nur ein normaler Zeiger. Und dieser Zeiger auf einen Zeiger soll auf den Heap zeigen, in dem dann ein Zeiger ist.

    Du verwechselst "die Variable (Zeiger)" und "die Variable, auf die die Variable (Zeiger) zeigt". Nachdem du px und ppx zugewiesen hast, sollst du die Zeiger dereferenzieren und den Variablen dahinter Werten zuweisen. Nix mit px und ppx noch mal was zuweisen, sondern den Werten dahinter - das hier ist also kompletter Blödsinn:

    px = &x;
    ppx = &px;
    

    Das Stichwort, wie man diesen Code korrigiert, habe ich dir bereits gegeben, dazu solltest du Tonnen an Material finden.

    Das hier ist auch Blödsinn:

    printf("x: %d\t Addr: %d\n", x, &x);
    printf("px: %d\t Addr: %d\n", px, &px);
    printf("pxx: %d\t Addr: %d\n", ppx, &ppx);
    

    Wie du vernünftig Zeiger ausgibst, zeigt dir die Dokumentation von printf.

    Und wenn du das alles gefixt hast, dann kannst du den Speicher auch wieder freigeben. Ich muss es wissen. Bei mir läuft's durch:

    x: 0	 Addr: 0x7ffdaa87202c
    px: 0x1da3010	 Addr: 0x7ffdaa872020
    pxx: 0x1da3030	 Addr: 0x7ffdaa872018
    


  • Okay, verstehe. Danke für die Hinweise.
    Habs jetzt geaendert. Habe aber dennoch das Gefühl das etwas nicht stimmt.:

    int x = 0;
      int *px = malloc(sizeof(int));
      int **ppx = malloc(sizeof(int *));
    
      *px = x;
      *ppx = &px;
    
      printf("x: %d\t Addr: %#x\n", x, &x);
      printf("px: %#x\t Addr: %#x\n", px, &px);
      printf("pxx: %#x\t Addr: %#x\n\n", *ppx, &ppx);
    
      free(px); 
      free(ppx);
    }
    


  • Möchtest du evtl den Wert haben, auf den px zeigt?
    Möchtest du evtl den Wert haben, auf den ppx letztendlich zeigt?

    Der Formatspecifier für Pointer ist nicht x
    x dient zur Ausgabe von Integern im Hexadezimalen Format.

    Ein Pointer ist kein Integer!



  • Achso okay, alles klar.

    Aber jetzt müsste alles stimmten wenn ich es richtig verstanden habe oder?

    void f1(){
      int x = 0;
      int *px;
      int **ppx;
    
      px = &x;
      ppx = &px;
    
      printf("x: %d\t Addr: %p\n", x, &x);
      printf("px: %p\t Addr: %p\n", *px, &px);
      printf("pxx: %p\t Addr: %p\n\n", ppx, &ppx);
    }
    
    void f2(){
      int x = 0;
      int *px = malloc(sizeof(int));
      int **ppx = malloc(sizeof(int *));
    
      *px = x;
      *ppx = &px;
    
      printf("x: %d\t Addr: %p\n", x, &x);
      printf("px: %p\t Addr: %p\n", px, &px);
      printf("pxx: %p\t Addr: %p\n\n", ppx, &ppx);
    
      free(px); 
      free(ppx); 
    }
    


  • Momolo2 schrieb:

    Aber jetzt müsste alles stimmten wenn ich es richtig verstanden habe oder?

    Leider nicht.

    Bei Zeigern/Pointern nimmt man p als Formatspecifier.
    Bei int dann die geünschte Darstellung: o, x, d oder i

    int x = 0;
      int *px;    //  *px  ist ein int.  px ist ein int* (Zeiger auf int)
      int **ppx;  // **ppx ist ein int.  
    
      px = &x;
      ppx = &px;
    
      printf("    x: %d\t Addr: %p\n", x, &x);
      printf("  *px: %d\t   px: %p\t Addr: %p\n", *px, px, &px);
      printf("**pxx: %d\t *ppx: %p\t  ppx: %p\t Addr: %p\n\n", **pc, *ppx, ppx, &ppx);
    }
    

    Stelle den Warnlevel vom Compiler auf Maximum.
    Der kennt die Formatspecifier für printf und gibt enstsprechende Warnungen aus, wenn da was nicht passt.



  • Das hier ist immer noch falsch:

    *px = x;
    *ppx = &px;
    

    px ist ein Zeiger auf int , folglich ist *px ein int , und &px ist ein Zeiger auf einen Zeiger auf int .
    ppx ist ein Zeiger auf einen Zeiger auf int , folglich ist *ppx ein Zeiger auf int .

    Warum also weißt du einen Zeiger auf einen Zeiger auf int ( &px ) einem Zeiger auf int ( *ppx ) zu?



  • Das Problem ist das ich dann den Speicherplatz nicht mehr freigeben kann mit:

    free(px); 
      free(ppx);
    


  • Hallo,

    //Der Pointer px wird im Stack angelegt, zeigt aber auf einen freien int
    //Speicher im Heap indem ein int gespeichert werden kann.
    int *px = malloc(sizeof(int));

    //Der Doppelpointer ppx wird im Stack angelegt, zeigt aber auf einen freien int* Speicher im Heap indem eine weitere Adresse gespeichert ist.
    int **ppx = malloc(sizeof(int *));

    //Du hast die Aufgabe richtig gelöst.
    //So ist es richtig:

    //Der Pointer px zeigt auf eine Adresse im Heap andem ein int gespeichert //werden kann.
    //So bekommt der Speicher im Heap also der Speicher aufdem px zeigt den Wert x //zugewiesen.
    *px = x;

    //Der Doppelpointer px zeigt auf einen Speicher im Heap indem eine Adresse //gespeichert werden kann. Mit der Anweisung, zeigt der Pointer pptx auf einen //Speicher im Heap, indem die Adresse von px gespeichert ist.
    *ppx = &px;

    printf("x: \t%d\t\t Addr: %p\n", x, &x);
    printf("px: \t%p\t Addr: %p\n", px, &px);
    printf("pxx: \t%p\t Addr: %p\n\n", ppx, &ppx);

    free(px);
    free(ppx);

    Also so müsste es aussehen:

    void f(){
    int x = 19;
    int *px = malloc(sizeof(int));
    int **ppx = malloc(sizeof(int *));
    *px = x;
    *ppx = &px;
    //Hier muss die Ausgabe hin
    free(px);
    free(ppx);
    }

    Lg, hoffe ich konnte helfen



  • Momolo3 schrieb:

    Das Problem ist das ich dann den Speicherplatz nicht mehr freigeben kann

    Solange du ppx nicht änderst (nicht verwechseln mit *ppx ), halte ich das für ein Gerücht.

    Und jetzt denkt mal darüber nach, was du *ppx da eigentlich zuweist.

    SebiX0 schrieb:

    //Du hast die Aufgabe richtig gelöst.

    Nein, hat er nicht. Er hat einen Teilaspekt der Aufgabe richtig gelöst.

    SebiX0 schrieb:

    //Der Doppelpointer px zeigt auf einen Speicher im Heap indem eine Adresse //gespeichert werden kann. Mit der Anweisung, zeigt der Pointer pptx auf einen //Speicher im Heap, indem die Adresse von px gespeichert ist.
    *ppx = &px;

    Du hast den Unterschied zwischen px und &px nicht kapiert, und deinen Code nicht mal durch einen vernünftigen Compiler gejagt. Der gibt nämlich völlig zu recht sowas aus:

    Zuweisung von inkompatiblem Zeigertyp
    

    Weil Zeiger auf int inkompatibel ist zu einem Zeiger auf einen Zeiger auf int .

    SebiX0 schrieb:

    Lg, hoffe ich konnte helfen

    Nein, hast du nicht. Mit deinem Beitrag hast du dafür gesorgt, dass Leute, die mehr Ahnung haben als du, deinen Unsinn korrigieren müssen. Das nächste Mal hau deinem Ego auf die Fresse, wenn es dir sagt, dass dein Halbwissen gut genug ist, um einen Beitrag zu schreiben.

    Außerdem fehlende Codetags. Zeigt, dass du den Vorschaubutton komplett ignoriert hast. Toll!



  • Oh man, jets bin ich durcheinander! 😕



  • Wie soll man da durcheinanderkommen? Lass die Codes durch einen vernünftigen Compiler laufen. Schau dir an, welcher davon eine Warnung produziert. So einfach.



  • Die Aufgabenstellung deines Lehrers ist laienhaft und falsch. Sie muss - bei wörtlicher Umsetzung - zu einem Fehler bei free() bzw. einem Speicherleck führen, den du auch schon beobachtet hast:

    > zwei lokale Variablen px und ppx und initialisieren Sie diese mit zwei Adressen, welche Speicher- bereiche auf dem Heap bezeichnen
    das erzwingt, dass jeweils malloc erforderlich ist

    > und den Inhalt der zweiten Variable auf dem Heap mit der Adresse der ersten Variablen auf dem Heap
    hier wird das Überschreiben des oben geforderten ppx-malloc verlangt -> Speicherleck + free()-Fehler (im besten Fall)

    void f(){ 
      int x = 123; 
      int *px; 
      int **ppx; 
    
      px =  malloc(sizeof(int)); 
      /* ppx = malloc(sizeof(int*)); muss raus wegen Nonsens deines Lehrers */
    
      *px = x; /*Initialisieren Sie den Inhalt der ersten Variable auf dem Heap mit dem Wert von x*/
      ppx = &px; /*den Inhalt der zweiten Variable auf dem Heap mit der Adresse der ersten Variablen auf dem Heap*/
    
      printf("x: %d\t Addr: %p\n", x, (void*)&x); 
      printf("px: %p\t Addr: %p\n", (void*)px, (void*)&px); 
      printf("pxx: %p\t Addr: %p\n", (void*)ppx, (void*)&ppx); 
    
      /* free(ppx); muss raus wegen Nonsens deines Lehrers */
      free(px);
    }
    

    http://ideone.com/RutTdA

    Fazit:
    - dein Lehrer hat keine Ahnung
    - du kannst wenig für die Fehler
    - entgegen dieses Beispiels lassen sich Zeiger auch zunächst mal ohne malloc erklären, dein Lehrer versagt auch hierbei, da er das nicht erkannt und in der Aufgabe Zeiger mit malloc verquickt hat



  • Wutz schrieb:

    [...]den Inhalt der zweiten Variable auf dem Heap[...]
    hier wird das Überschreiben des oben geforderten ppx-malloc verlangt -> Speicherleck + free()-Fehler (im besten Fall)

    Blödsinn. Die Formulierung ist unglücklich gewählt, besagt aber dennoch eindeutig, dass hier die Variabel auf dem Heap geändert werden soll - worauf also ppx zeigt, was man auch *ppx nennt. Das "die zweite Variabel auf dem Heap" bezieht sich auf px , welches bereits auf einen int im Heap zeigt; das ist die Erste. Die Zweite ist die, die die Adresse in px halten soll.

    Wutz schrieb:

    - dein Lehrer hat keine Ahnung

    Würde ich pauschal nicht sagen. Vielleicht hat er auch einfach nur Schiss, dass Leute irgendwie nicht kapieren, was Zeiger sind, wenn er nicht explizit klar macht, dass das auch nur Variablen sind. Leute, die z.B. Arrays mit Zeigern verwechseln, gibt es zuauf.

    Oder der Lehrer hat wirklich keine Ahnung.



  • Momolo3 schrieb:

    Das Problem ist das ich dann den Speicherplatz nicht mehr freigeben kann mit:

    free(px); 
      free(ppx);
    

    Kann passieren, wenn beim Umgang mit Zeigern die Adressen von allokiertem Speicher vermurkst werden. Dadurch entstehende Probleme bei der Speicherfreigabe lassen sich aber ganz einfach verhindern (sofern der Code nicht schon vor free() abgestürzt ist):

    void f2 ()
    {
        // die folg. void-Zeiger sollen einzig nur verwendet werden, um die 
        // Adressen des für px und ppx mit malloc() allokierten Speichers zu
        // retten und diesen Speicher später mit free() wieder freizugeben.
        void *px_sav = NULL, *ppx_sav = NULL;
    
        px = malloc(...);
        ppx = malloc(...);
        px_sav = px;
        ppx_sav = ppx;
    
        // vor weiterer Verwendung von px bzw. ppx sollte geprüft werden, ob
        // malloc() überhaupt Speicherplatz allokieren konnte und nicht etwa
        // NULL-Zeiger zurückgegeben hat.
        if (NULL != px) && (NULL != ppx) {
            // ... weitere Verwendung von px und ppx
        }
        // Speicherfreigabe vor Rückkehr der Funktion:
        if (NULL != px_sav) {
            free(px_sav);
            px_sav = NULL;  // kann hier auch entfallen
        }
        if (NULL != ppx_sav) {
            free(ppx_sav);
            ppx_sav = NULL;  // kann hier auch entfallen
        }
        return;
    }
    

Log in to reply