dynamische Allokierung, malloc, calloc



  • 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?



  • Du wolltest 8 Byte haben und die hast du auch bekommen.
    C überprüft nicht die Bereichsgrenzen.

    Der Speicher ab dem 8. Byte kann dann von einem anderen malloc belegt werden.



  • aber wie erklärt sich dass der speicher trotzdem nutzbar ist obwohl er nicht von einem anderen malloc besetzt ist?



  • Im Kino kannst du 8 Plätze reservieren.
    Der Kinosaal hat aber mehr Plätze als deine 8. Auf die kannst du dich auch setzen - bis einer kommt, dem die Plätze zugewiesen wurden. Dann geht der Ärger los.

    aber wie erklärt sich dass der speicher trotzdem nutzbar ist obwohl er nicht von einem anderen malloc besetzt ist?

    Der Speicher ist doch vorhanden, nur nicht zugeteilt. C macht wie gesagt keine Überprüfung, ob du über Grenzen schreibst.



  • Weil malloc nichts anderes macht, als den Speicherplatz zu verwalten.
    Stell dir einfach vor, malloc ist der Wart vom Parkplatz, der dir einen Stellplatz zuweist. Wenn jetzt jemand auf den Parkplatz fährt, ohne dass der Wart es mitbekommt, dann kann es passieren, dass der Wart einen Stellplatz vergibt, wo sich der Schwarzparker hingestellt hat. Dann kracht es natürlich an der Stelle. Solange aber niemand anderes dort parkt, gibt es kein Problem.


Anmelden zum Antworten