dynamische Allokierung, malloc, calloc



  • Student123 schrieb:

    Würde ich mir mit dem Code

    main(){
      int size = 8;
      int a;
      
      a = (int)malloc(size * sizeof(int));
    }
    

    welches als Ergebnis 146903048 liefert, "146903048" Bytes freimachen?

    Wenn ja, dann versteh ich es so allmählich glaub ich 🙂

    Nein. Das macht so keinen Sinn. Du sagst malloc() wieviel Speicher du reservieren willst, in deinem Fall 8 mal die Größe eines int, also Platz für 8 int hintereinander im Speicher. Der Rest ist schlicht falsch. malloc gibt dir einen Zeiger auf den reservierten Speicherbereich zurück, also eine Adresse, und im Fehlerfall (z.B. nicht ausreichend Speicher frei) den NULL-Zeiger. Korrekt wäre dein Beispiel so:

    int main(void){
      int size = 8;
      int *a;
    
      a = malloc(size * sizeof(int));
      if (a) {
        /* mache was mit a */
    
        /* Speicher wieder freigeben */
        free(a);
      }
      else {
        printf ("Fehler");
      }
    }
    


  • Die Aussage deines Prof. beruht darauf, das in den Beispielen von Wutz die Funktionen strcpy und puts nicht mehr unterscheiden können ob die Daten zu einem array oder einem dynamischen Speicher gehören.

    Die Funktionen in denen array bzw. zeiger deklariert sind können das.

    Man kann Zeigern die Adresse eines Arrays zuweisen, aber nicht umgekehrt. ⚠

    zeiger = array;  // geht. zeiger Zeigt auf da erste Element von array
    array = zeiger;  // geht nicht.
    

    Beachte: array ist nicht das gleiche wie array[0].
    Zudem braucht zeiger selber auch Speicherplatz.

    PS: Die 146903048 ist die Adresse ab der dein geforderte Speicher liegt.
    mit free(a) sagst du dann: den Speicher ab Adresse 146903048 freimachen.
    Wieviel SPeicher das ist erfährt free aus internen Daten von malloc.



  • Also habe ich mit meinem Code

    main(){
      int size = 8;
      int a;
    
      a = (int)malloc(size * sizeof(int));
    }
    

    ab der Adresse "146903048" 8x4=32 Bytes reserviert?



  • Genau.



  • Student123 schrieb:

    Würde ich mir mit dem Code

    main(){
      int size = 8;
      int a;
      
      a = (int)malloc(size * sizeof(int));
    }
    

    welches als Ergebnis 146903048 liefert, "146903048" Bytes freimachen?

    Komplett falsch.
    malloc liefert einen Zeiger zurück, du solltest den obigen Text nicht nur lesen sondern auch umsetzen, du hast nämlich die Adresse des von malloc gelieferten belegten Speicherbereiches einem int zugewiesen, das ist natürlich Unsinn.



  • Ok, alles klar.

    Jetzt stehen noch einige Fragen aus. Wenn ich mit malloc arbeite wie im ebigen Beispiel, muss ich es in einem Feld, Pointer oder in einer Variable abspeichern?

    Wutz hat eben nämlich a als Pointer deklariert aber als Variable genutzt.

    Wenn ich mit einem Feld arbeiten muss und angenommen ich will das Feld i mit i * i füllen, wie müsste ich da vorgehen?



  • Vom Prinzip hast du das verstanden, aber dein Code hat noch Fehler.
    Zeiger werden in C mit dem * davor deklariert.

    main(){
      int size = 8;
      int *a; // a ist ein Zeiger, *a ist ein int
    
      a = (int *)malloc(size * sizeof(int));
    
      *a      = 4;  // in das erste  Element von a wird eine 4 geschrieben.
      *(a+1)  = 5;  // in das zweite Element von a wird eine 5 geschrieben.
    //  :warning:  Der Compiler weiß wie groß ein int ist und zählt schon richtig weiter  (hier +(1*4))               
    }
    

    * ist der Dereferenzierungs-Operator



  • #define ANZAHLELEMENTE 8
    int i,*zeiger = malloc(ANZAHLELEMENTE*sizeof(int));
    for( i=0;i<ANZAHLELEMENTE;++i )
      zeiger[i] = i*i;
    for( i=0;i<ANZAHLELEMENTE;++i )
      printf("\n%d",zeiger[i]);
    free(zeiger);
    


  • aber benutzt du beim deklarieren den Pointer a(also 😉 und weiter unten beim Code wo das mit malloc gemacht wird das einfache a?



  • Nur zur Klarstellung:
    Das geht beides.

    zeiger[i] ist gleichbedeutend mit *(zeiger+i)

    Was wieder Verwirrung über den Unterschied zwischen Zeigern und Arrays stiften wird. 🙂



  • hmm.. ok.

    main(){
                  int size = 8;
                  int *ptr;
                  int i;
                  int grenze;
    
                  *ptr = (int)malloc(size * sizeof(int));
                  grenze = size * sizeof(int);
    
                   for(i = 0; i<grenze; i++){
                     ptr[i] = i * i;
                   }
    
    }
    

    so würde ich size * sizeof(int) Felder mit i * i füllen?



  • Beim deklarieren sagst du *int a; a ist ein Zeiger auf ein int. Oder zum merken: *a ist ein int.

    malloc liefert dir einen Zeiger (auf void) und den musst du dann zuweisen: a = malloc(..);

    int *a,
    
    a = malloc(...);
    
    *a = 5;
    printf("Der Inhalt von %p ist %d\n", a, *a);
    
    free(a);
    

    ----------------------
    Gerade noch gesehen:
    Nein eben nicht:

    main(){
                  int size = 8;
                  int *ptr;
                  int i;
                  int grenze;
    
    // FALSCH     *ptr = (int)malloc(size * sizeof(int));   // *ptr ist ein int
                  ptr = (int *)malloc(size * sizeof(int));  // ptr ist der Zeiger auf int
    // FALSCH     grenze = size * sizeof(int);
                  grenze = size ;  // Der Compiler weiß wie groß ein int ist!
                                   // Du hast nur 8 int, keine 32
    
                   for(i = 0; i<grenze; i++){
                     ptr[i] = i * i;  // Beim Zugriff achtet der Compiler auf die richtigen Offsets
                   }
    

    }



  • Hm, ok alles klar. Ich nehme das nun einfach mal so hin. Ich muss eine Aufgabe mit malloc lösen, die wie folgt beschrieben ist:

    Erzeugen Sie in einem Programm zu einer Folge von Zahlen, die vom Benutzer
    einzugeben sind, das Zahlendreieck, in dem sich ab der zweiten Zeile jede Zahl als
    Summe der darüberliegenden Zahl und deren rechter Nachbarzahl ergibt.
    Die Anzahl der zu behandelnden Zahlen ist vom Benutzer einzugeben, dann ist ein
    Feld geeigneter Größe dynamisch (mit malloc oder calloc) zu erzeugen.

    Das war jene Aufgabe, wo der Prof von mir wollte dass ich es erst statisch mache. Die dynamische Version gibts dann am Montag.



  • Hey,

    machen wir doch einmal gleich da weiter, wo wir aufgehört haben. Unzwar versuche ich grade das obrige Problem zu lösen.

    Ich habe folgenden Code geschrieben:

    //Deklaration
          int size = 0;
          int *zahlen;
          int i;
    
          //Eingabe der Größe
          printf("Wieviele Zahlen?\n");
          scanf("%d",&size);
    
          //Reservierung der Größe
          zahlen = (int *)malloc(size * sizeof(int));
    
          //Eingabe der Zahlen
          for(i = 0; i<size;i++){
    	      printf("Bitte geben Sie %d Zahlen ein:\n",size);
    	      scanf("%p",zahlen[i]);
          }
    

    Aber ich bekomme nach Eingabe der ersten Zahl ein "Segmentation fault".

    Wieso?



  • 1. musst du an scanf Adressen (Zeiger) übergeben

    2. Was willst du denn mit "%p" bei scanf erreichen?
    Probier mal %i oder %d.

    scanf("%i",&zahlen[i]);
    //oder 
    scanf("%i",zahlen+i);
    


  • 3. bei malloc immer auf Erfolg (!= NULL) testen ⚠



  • wie dumm von mir.. Ja danke, jetzt funktioniert es auch.



  • Hallo Freunde,

    Ich bins wieder mit der gleichen Thematik. Ich glaube, ich werde diese dynamische Allokierung niemals lernen..

    Also das letzte mal, als ich hier schrieb, dachte ich, dass man mit malloc einen Speicherplatz reserviert und dieser nur in einer bestimmten Grenze vorhanden ist.
    Das untrige Beispiel beweist mir aber das Gegenteil...

    int *ptr;
    	  int size = 2;
    	  int i = 455;
    
    	  ptr=(int*)malloc(size * sizeof(int));
    	  printf("%p\n",ptr);
    
    	  ptr[i] = 233465;
    
    	  printf("%d\n", ptr[i]);
    

    Nach meinem Verständnis habe ich Speicherplatz für 8 Bytes reserviert. Ich speichere aber im 455. Feld von ptr eine Zahl ab und gebe sie wieder aus. Das alles funktioniert, obwohl ich nicht einmal soviel Platz reserviert habe.

    Wie ist das zu verstehen?



  • Undefiniertes Verhalten: Kann funktionieren, muss aber nicht. Prinzipiell kann alles passieren, bis hin zum Kollaps von Raum und Zeit. Praktisch scheint es hier zu funktionieren, weil du noch im gleichem Segment bist, was dann nicht unbedingt erkannt wird (sprich keine irgendwas-violation).



  • d.h. ich bin bis i = 7 im "sicheren" Bereich und ab 7 nicht mehr?


Anmelden zum Antworten