dynamische Allokierung, malloc, calloc



  • Hallo Freunde,

    Ich habe da so ein kleines Problemchen. Wir haben in den letzten Vorlesungen die berühmte "Dynamische Allokierung" durchgenommen. Das Prinzip dessen ist mir zwar klar(den Speicherplatz eines Arrays oder eines Pointers dynamisch, also durch den Benutzer, eingeben), nur der Syntax und die Logik im Programmcode noch nicht so ganz.

    Wir haben ein Beispiel gehabt, der wie folgt aussieht:

    #include <stdio.h>
    #include <stdlib.h>
    
    main(){
    
    int anzahl, size;
    int *ptr;
    int i;
    
    printf("Anzahl der allokierenden Daten:\n");
    scanf("%d",&anzahl);
    printf("Größe der zu allokierenden Typen(in Bytes):\n");
    scanf("%d",&size);
    
    ptr = (int*)malloc(anzahl*size);
    
    for(i = 0;i<anzahl;i++){
    ptr[i] = i * i;
    }
    
    printf("Ausgabe:\n");
    for(i=anzahl-1;i>=0;i--){
    printf("Feldelement %d = %d\n",i,ptr[i]);
    }
    }
    

    Was macht der Befehl "ptr = (int*)malloc(anzahl*size);"? Und wie sehr wirkt er sich auf die Variable(Pointer) "*ptr" aus?

    Liebe Grüße,

    Student.



  • malloc besorgt dir Speicherplatz.
    Du mußt dir merken wo malloc den besorgt hat.
    Die Adresse schreibst du in einen Zeiger (ptr).
    Dein Zeiger ist für den Typ int.
    Darum musst du den Zeigertyp den malloc liefert (auf void) in auf int wandeln.

    In ptr steht die Adresse des geforderte Speicherbereichs.
    Oder NULL wenn es nicht geklappt hat.

    Das size was du nutzt ist dafür gedacht die Größe des Datentyps zu berücksichtigen.

    ptr = (int*)malloc(anzahl*sizeof(int));
    


  • Hi,

    um es evtl. noch etwas deutlicher zu machen. Ein Array ist ja nichts weiter als ein "block" Daten die hinter einander im Speicher liegen:

    Array A (z.b. int A[ 5 ])
    
    +-------------------+
    | sizeof( int ) * 0 | <=> A[ 0 ]
    +-------------------+
    | sizeof( int ) * 1 | <=> A[ 1 ]
    +-------------------+
    | sizeof( int ) * 2 | <=> A[ 2 ]
    +-------------------+
    | sizeof( int ) * 3 | <=> A[ 3 ]
    +-------------------+
    | sizeof( int ) * 4 | <=> A[ 4 ]
    +-------------------+
    

    So A[ 0 ] liegt nun irgendwo in deinem Arbeitspeicher z.B. bei Adresse 0x12345678. Ab dieser Stelle im Speicher sind nun die folgenden Stellen für den Array reserviert. Da man aber evtl. zur Laufzeit ja manchmal die Größe ändern möchte, bedient man sich z.B. realloc, malloc und weiß der Geier was noch. realloc z.B. alloziert neuen Spiecher für eine gewünschte Größe z.B. für 20 Integralzahlen (int) und kopiert die sogar deine momentanen Daten in den neuen Bereich anschließend returned dir realloc genau wie malloc die Stelle im Speicher, also die Adresse, an der dein Array nun liegt bzw. beginnt.

    Lg Tobi



  • Student123 schrieb:

    zwar klar(den Speicherplatz eines Arrays oder eines Pointers dynamisch, also durch den Benutzer, eingeben)

    Dynamische Speicherzuweisung für ein Array? Vielleicht sollte ich mich in eure Vorlesung setzen, da kann ich noch was lernen 😮



  • Wutz schrieb:

    Student123 schrieb:

    zwar klar(den Speicherplatz eines Arrays oder eines Pointers dynamisch, also durch den Benutzer, eingeben)

    Dynamische Speicherzuweisung für ein Array? Vielleicht sollte ich mich in eure Vorlesung setzen, da kann ich noch was lernen 😮

    Mit realloc, kannst du durch aus den Speicherplatz für ein Array dynamisch vergrößern oder verkleinern, das dieser nach der Operation nicht zwingend an der gleichen Adresse beginnt ist allerdings nicht immer der Fall. Dennoch ist dies doch dynamisch oder nicht?

    Lg Tobi



  • Nein.



  • Hallo,

    Ich versuch das schon die ganze Zeit zu verstehen aber "no way". Das Prinzip scheint mir ja irgendwie klar zu sein aber der Rest...

    Vielleicht kann mir der ein oder andere genauere Infos geben?

    Herzlichen Dank im voraus und frohes neues Jahr,

    Student.



  • Wutz schrieb:

    Student123 schrieb:

    zwar klar(den Speicherplatz eines Arrays oder eines Pointers dynamisch, also durch den Benutzer, eingeben)

    Dynamische Speicherzuweisung für ein Array? Vielleicht sollte ich mich in eure Vorlesung setzen, da kann ich noch was lernen 😮

    Ja, nennt sich Variable Length Array.



  • Also es würd mich freuen wenn einer mir das obrige Beispiel etwas detaillierter erklären könnte.



  • Ich probier es mal

    #include <stdio.h>
    #include <stdlib.h>
    
    main(){
    
      int anzahl, size;
      int *ptr;  //hier wird ein Zeiger auf int deklariert. Der zeigt erstmal nirgendwo hin. *ptr ist ein int, ptr ist eine Adresse
      int i;
    
      printf("Anzahl der allokierenden Daten:\n");
      scanf("%d",&anzahl);
    //  printf("Größe der zu allokierenden Typen(in Bytes):\n");
    //  scanf("%d",&size);
      size = sizeof(int); // ptr ist ein Zeiger auf int !!
    
      ptr = (int*)malloc(anzahl*size); // malloc besorgt dir soviel Speicherplatz in Bytes, wie in den Klammern angegeben ist
                                       // Und die Adresse auf den Speicher wird in ptr abgelegt
                                       // Damit der Compiler nicht meckert wird eine Typumwandlung (cast) mit (int*) erzwungen.
    
      for(i = 0;i<anzahl;i++){
        ptr[i] = i * i;    // Hier schlägt die Verwandtschaft von Array und Zeigern durch.
                           // Du weist dem i. Element einen Wert zu.
    // *(ptr+i) = i * i;   // Geht auch. Der Compiler weiß (dank int *ptr) wie viel Bytes er weiter gehen muss 
      }
    
      printf("Ausgabe:\n");
      for(i=anzahl-1;i>=0;i--){
        printf("Feldelement %d = %d\n",i,ptr[i]);
      }
    }
    


  • Tim schrieb:

    Wutz schrieb:

    Student123 schrieb:

    zwar klar(den Speicherplatz eines Arrays oder eines Pointers dynamisch, also durch den Benutzer, eingeben)

    Dynamische Speicherzuweisung für ein Array? Vielleicht sollte ich mich in eure Vorlesung setzen, da kann ich noch was lernen 😮

    Ja, nennt sich Variable Length Array.

    Nur C99 und undefiniertes Verhalten bei nicht ausreichend vorhandenem freien Hauptspeicher.



  • Hallo Freunde,

    entschuldigt bitte meine Verspätung. Ich war über Silvester im Ausland..

    Vielen Dank an DirkB für den Code. Leider habe ich immer noch nicht wirklich viel verstanden. Ich habe eine Aufgabe probiert und meinen Professor angeschrieben. Der antwortete mir, dass ich die Aufgabe erst einmal mit Feldern machen soll(also statische Allokierung) und wir zusammen in der Übung es dynamisch machen werden. Er schrieb dazu, dass "es im Prinzip dasselbe" ist.

    Ich finde auch leider im Internet keine Literatur dazu, wo ich mich schlau machen könnte..

    Weiß da jemand was?

    Liebe Grüße,

    Student.



  • T0bi schrieb:

    Mit realloc, kannst du durch aus den Speicherplatz für ein Array dynamisch vergrößern oder verkleinern, das dieser nach der Operation nicht zwingend an der gleichen Adresse beginnt ist allerdings nicht immer der Fall. Dennoch ist dies doch dynamisch oder nicht?

    Kannst Du mir das bitte mal an einem konkreten Code demonstrieren?
    Also, das:

    int arr[100];
    

    ist ein Array mit Platz für 100 Integerwerte. Nun zeig mir bitte, wie ich das dynamisch vergrößern/verkleinern kann.



  • Mal abgesehen von pseudodynamischen VLA, welche eh nur den Stack belasten und ohne Fehlerbehandlung auskommen müssen, ist die dynamische Speicherbelegung in C ein sehr wesentliches Kriterium, ohne das keinerlei professioneller Code auskommt.
    Dynamische Speicherbelegung ist gekennzeichnet durch die Funktionen malloc,calloc,realloc und free welche immer einen Zeiger zurückliefern (und kein Array, wie bei deinem Eingangsstatement).

    Beispiel statischer Speicher:

    #define GROESSEINBYTES 100
    char array[GROESSEINBYTES];
    strcpy(array,"blafasel");
    puts(array);
    

    Beispiel dynamischer Speicher:

    #define GROESSEINBYTES 100
    char *zeiger;
    zeiger=malloc(GROESSEINBYTES);
    strcpy(zeiger,"blafasel");
    puts(zeiger);
    free(zeiger);
    

    Wie du siehst, ist dynamische Speicherbelegung aufwändiger und wahrscheinlich meinte dein Prof. deshalb, du sollst es erstmal mit statischer Speicherbelegung sprich Arrays versuchen.
    Und um der Frage gleich vorzubeugen: NEIN, Array und Zeiger sind NICHT dasgleiche und schon gar nicht dasselbe, nur snippetgläubige Laien behaupten dieses.



  • Wutz schrieb:

    ist die dynamische Speicherbelegung in C ein sehr wesentliches Kriterium, ohne das keinerlei professioneller Code auskommt.

    Janeisklar...



  • Hallo,

    danke für deine Antwort, Wutz. Naja.. mein Prof. sagt uns nämlich immer, dass es "im Prinzip" keinen Unterschied zwischen Zeiger und Felder gibt. Naja, wie auch immer..

    Dynamische Allokierung mit Strings haben wir bisher auch nie gemacht. Mein Prof. ist eher einer, der Mathefunktionen und -aufgaben mit C verbindet. Ich habe mittlerweile doch eine Homepage gefunden, wo Sachen wie dynamische Allokierung und so erklärt wird(http://r4r.co.in).

    Von den Skripten ausgehend habe ich mal folgendes versucht und habe auch folgende Frage:

    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 🙂

    Liebe Grüße,

    Student.



  • Student123 schrieb:

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

    Zonk!



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


Anmelden zum Antworten