Dynamische Speicherverwaltung



  • Hallo liebe Community!
    ich bin gerade dabei die dynamische speicherverwaltung zu lernen.

    jetzt habe ich folgendes Programm gegeben welches einen string in einen dynamisch reservierten speicher einliest dieser wird wenn er voll ist erweitert und bei EOF wird der string verkehrt ausgegeben.

    Ich versteh den Code allerdings noch nicht komplett könnte mir irgendjemand genau erklären was hier speichertechnisch genau passiert da sich die speicherverwaltung ja schlecht per printf oder so nachverfolgen lässt.

    Vielen Dank im Voraus !
    Lg 🙂

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char* argv[])
    {
        char* memory = NULL;
        char* tmp = NULL;
        unsigned int size = 0;
    	unsigned int i;
    
        char c = 0;
    	int a;
        while((c = fgetc(stdin)) != EOF)
        {
            size++;
    		printf("%d ",size);
            tmp = (char*)malloc(size);
    
            if(tmp == NULL)
            {
                printf("Error: Out of memory!\n");
                return 1;
            }
            //memcpy(tmp,memory,size-1);
    		//for(a = 0; a < size-1; a++)
            memory = (char*)realloc(memory,size);
            if(memory == NULL)
            {
                printf("Error: Out of memory!\n");
                return 1;
            }
    
            for(a = 0; a < size; a++)
            memory[size-1] = c;
            free(tmp);
        }
    
        for(i = size; i>0; i--)
        {
            printf("%c",memory[i-1]);
        }
        printf("\n");
        free(memory);
        return 0;
    }
    


  • Hanna245 schrieb:

    Ich versteh den Code allerdings noch nicht komplett ...

    Ich auch nicht, denn der ist voller Fehler.

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char* argv[])
    {
        char* memory = NULL;
        char* tmp = NULL;
        unsigned int size = 0;
    	unsigned int i;
    
        char c = 0;  // falscher Typ
    	int a;
        while((c = fgetc(stdin)) != EOF) // Das geht nicht, wenn c ein char ist. C sollte ein int sein, so wie der Rueckgabewert von fgetc()
        {
            size++;
            printf("%d ",size);
            tmp = (char*)malloc(size);  // Warum dieses malloc? 
    
            if(tmp == NULL)
            {
                printf("Error: Out of memory!\n");
                return 1;
            }
            //memcpy(tmp,memory,size-1);
    		//for(a = 0; a < size-1; a++)
            memory = (char*)realloc(memory,size);  
            if(memory == NULL)
            {   
                printf("Error: Out of memory!\n");
                return 1;
            }
    
            for(a = 0; a < size; a++)  // warum dies Schleife?
              memory[size-1] = c;  // size-mal das letzte Zeichen beschreiben  :confused: 
            free(tmp);  // bis hier wurde tmp nicht einmal benutzt.
        }
    // eine Terminierung mit '\0' ist hier zwar nicht noetig, aber wuenschenswert
    
        for(i = size; i>0; i--)
        {
            printf("%c",memory[i-1]);  // und immer mit dem groesste Hammer (prinf) Ein putchar (memory[i-1]); reicht doch
        }
        printf("\n");
        free(memory);
        return 0;
    }
    

    Hanna245 schrieb:

    per printf oder so nachverfolgen laesst.

    printf geht. Du kannst dir die Zeiger mit %p ausgeben lassen. Und wenn der String terminiert ist, kannst du auch %s benutzen.

    Oder so waere der Debugger.



  • Hallo 🙂 alles klar dann bin ich schon mal ein bissi erleichtert 😉
    kannst du mir bitte sagen wie ein Programm aussehen soll wenn ich einfach einen String einlesen möchte wie hier und den Speicher wenn er voll ist erweitere ?
    Ich versteh bei dem Programm nicht wo das geschehen soll ?
    Fehlt da nicht irgendwo eine if abfrage ob der speicher voll ist ?

    Lg



  • Es wird jedesmal mit realloc Speicher besorgt, der ein Zeichen mehr Platz hat als der vorhegehende Speicher.
    realloc sorgt sogar fuer das umkopieren der Daten, falls das noetig ist.

    Wenn kein Speicher (in ausreichender Groesse) mehr frei ist, gibt realloc NULL zurueck. Und das wird ja geprueft.
    Allerdings ist es bloed den Zeiger auf den Speicher dabei zu ueberschreiben.
    Wenn wirklich kein Speicher mehr frei ist, geht dir so der Zugriff auf die bisher gelesenen Daten verloren.

    Das vergroessern um jeweils ein Zeichen ist allerdings sehr ineffektiv.

    Bei http://www.cplusplus.com/reference/cstdlib/realloc/ ist auch ein Beispiel fuer das Einlesen von int. sizeof(char) ist immer 1. Darum kann man es (wie bei dir) weglassen.



  • Hallo Dirk !
    Danke für die Erklärung!

    Ich habe es jetzt mal selbst versucht mittels blockweise Speicher allokieren und das sieht bei mir jetzt so aus:

    temp_array = (char*)malloc(BLOCK_SIZE);
    
      if(temp_array == NULL)
      {
        printf("Error: Out of memory!\n");
        return 1;
      }
    
      while((c = fgetc(stdin)) != EOF)
      {
        size++;
    
        if(size == BLOCK_SIZE)
        {
          size = BLOCK_SIZE + size;
          temp_array = (char*)realloc(temp_array,size);
    
          if(temp_array == NULL)
          {
            printf("Error: Out of memory!\n");
            return 1;
          }
        }
    

    stimmt das so? Lg 🙂


  • Mod

    Hanna234 schrieb:

    stimmt das so? Lg 🙂

    Sieht falsch aus. size scheint bei dir zwei verschiedene Bedeutungen zu haben: Die allokierte Größe und die Länge der Zeichenkette. Außerdem wird nirgendwo etwas in die Zeichenkette geschrieben, das eigentliche Ziel der Aktion also vollkommen verfehlt.

    Wenn man ganz streng ist, dann ist auch die Technik beim realloc falsch. Falls realloc nämlich NULL zurück geben sollte, dann wird der alte Speicher nicht frei gegeben. Da du beim realloc aber deinen einzigen Zeiger auf diesen Speicher überschreibst, hättest du dann ein schönes Speicherloch produziert, weil du an diesen Speicher nie wieder rankommst. Das ist aber Haarspalterei, die anderen Probleme sind dringender.



  • Hallo - okay schon mal danke ... also "size" sollte eigentlich die Anzahl der eingelesen Zeichen sein Lg


  • Mod

    Hanna234 schrieb:

    Hallo - okay schon mal danke ... also "size" sollte eigentlich die Anzahl der eingelesen Zeichen sein Lg

    Und was macht dann Zeile 15?



  • ja stimmt da wird size ja überschrieben dann sollte ich eine weitere variable zb. length für die länge des strings nehmen oder ? 🙂


  • Mod

    Hanna234 schrieb:

    ja stimmt da wird size ja überschrieben dann sollte ich eine weitere variable zb. length für die länge des strings nehmen oder ? 🙂

    Ja. Für dynamische Felder bieten sich drei Variablen an:
    1. Zeiger auf Anfang des reservierten Bereichs.
    2. Zeiger auf Ende der Nutzdaten oder Länge der Nutzdaten.
    3. Zeiger auf Ende des reservierten Bereichs oder Länge des reservierten Bereichs.

    Wenn du die drei in ein struct verpackst und passende Funktionen zur Benutzung anbietest, dann hast du eine Art string-Klasse, wie man sie aus objektorientierten Sprachen kennt. Das ist für den Anfang ziemlicher Overkill, aber wenn es in der Benutzung solcher Zeichenketten mal intensiver wird, ist das ganz nützlich.


Log in to reply