Wie herausfinden ob char* malloced ist?



  • Hi,

    angenommen ich habe eine Funktion replace die eine übergebenen char* mit neuem Inhalt füllt. Wie kann ich herausfinden ob der Speicher für den char* mit einem malloc alloziert wurde?

    Wurde er mit malloc alloziert muss ich den Speicher ja hier freigeben, kann aber nix freigeben wenns nicht von malloc kommt.

    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    
    void replace(char **toReplace) {
    
            // free einkommentiert: Invalides free bei replace(&str2);
            // free auskommentiert: Memory Leak bei replace(&str1);
    	free(*toReplace); 
    
    	*toReplace = strdup("Hmpf");
    }
    
    int main () {
    
    	char *str1;
    	char *str2;
    
    	str1 = (char *)malloc(4);
    	strcpy(str1, "Bar");
    	replace(&str1);
    	printf("Bar replaced");
    	free(str1);
    
    	str2 = "Foo";
    	replace(&str2);
    	printf("Foo replaced");
    
    	return 0;
    }
    

    Diese Funktion liegt innerhalb einer Bibliothek, ich kann also nicht garantieren dass immer ein malloced bzw. stacked char* übergeben wird.

    Juri



  • an sich gibt es da keine Möglichkeit um das Festzustellen.

    Das muss aber auch nicht sein, da du kein MemoryLeak hast
    [cpp]
    str1 = (char *)malloc(4);
    strcpy(str1, "Bar");
    replace(&str1);
    printf("Bar replaced");
    free(str1);
    [/cpp]

    ps:

    In String-Literale sollte man nicht Reinschreiben. Kann im zusammenhang mit String-Pooling böse Folgen haben. Kopiere den Text lieber in ein Lokales Array.

    str2[] = "Foo";
    


  • Allokiere in einer Bibliotheksfunktion keinen Speicher, sondern überlasse das dem Benutzer.



  • JuriGlx schrieb:

    Diese Funktion liegt innerhalb einer Bibliothek, ich kann also nicht garantieren dass immer ein malloced bzw. stacked char* übergeben wird.

    das kannst du nicht herausfinden und es ist *nicht* deine Aufgabe, den Speicher der andere für sich reservieren, freizugeben und auch dazu eine schlechte Idee. In der Doku musst du nur darauf hinzuweisen, dass die Referenz auf allozierten Speicher unter Umständen verloren gehen kann und deshalb eine Kopie erstellt werden soll.

    Warum ich sage, dass es eine schlechte Idee wäre: Du weißt nicht, wer wirklich darauf zugreift noch wie viele Referenzen auf den Speicher gibt. Bsp:

    void *mem = malloc(...);
    
    start_thread_one(mem);
    start_thread_two(mem);
    start_thread_cleanup(mem); /* dieser Thread gibt den Speicher frei */
    
    /* an der Stelle benötige ich den Wert von mem nicht mehr */
    replace(&mem);
    printf("%s\n", (char*) mem);
    ...
    

    du hast 3 Threads, d.h. du hast mind. 3 weitere Referenzen auf den Speicher, den du mit malloc reserviert hast. Wenn replace den Speicher freigenen würde, dann wäre der Speicher nicht mehr für Threads gültig. Das Programm wird am wahrscheinlichsten abstürtzen. Bei meinem Bsp gibt es thread 3, der den Speicher freigibt, sobald er nicht mehr benötigt wird (weil ich mir die Steuerung so definiert habe). Es wäre also nicht gut, wenn replace , eine Funktion einer anderen Bibliothek, plötzlich meinen Speicher freigibt.



  • Abgesehen davon hat man in der Praxis auch oftmals Speicher mit anderen Mechanismen allokiert als mit malloc.



  • Hi,

    Danke für die Antworten.

    Also in der Bibliotheksfunktion den Speicher nicht freigeben, soweit so gut.

    tippgeber schrieb:

    Allokiere in einer Bibliotheksfunktion keinen Speicher, sondern überlasse das dem Benutzer.

    Das strdup besorgt sich ja implizit auch Speicher via malloc, d.h. das kann ich dann nicht verwenden.
    Also sowas schreiben und den Benutzer der Funktion die Größe des benötigten Speichers raten lassen?

    /// Speicher muss alloziert sein und size ist dessen Größe.
    /// Gibt -1 zurück wenn der Speicher nicht ausreicht, 0 sonst.
    int replace(char **toReplace, unsigned int size) {
    
        if(4 >= size) return -1;
    
        strcpy(*toReplace, "Hmpf");
        return 0;
    }
    


  • JuriGlx schrieb:

    angenommen ich habe eine Funktion replace die eine übergebenen char* mit neuem Inhalt füllt. Wie kann ich herausfinden ob der Speicher für den char* mit einem malloc alloziert wurde?

    ausser typ und adresse gibt C einem keine weiteren speicherattribute bekannt. du könntest aber, anstatt mit 'rohen' pointern zu arbeiten, eine struct nehmen, die zusätzliche infos über den speicher hat.

    z.b. sowas

    typedef enum memtype
    {
      MEM_OTHER,      // nicht vom heap
      MEM_HEAP,       // malloc
    } memtype_t;
    
    typedef struct extended_charptr
    {
      char *ptr;          // der eigentliche zeiger
      memtype_t type;     // speichertyp
    } extended_charptr_t;
    

    und wenn du dann speicher allozierst machste z.b. sowas

    extended_charptr_t from_heap (size_t size)
    {
      extended_charptr_t e;
    
      e.ptr = malloc (size);
      if (e.ptr == 0)
      {
        e.type = MEM_OTHER;
      }
      else
      {
        e.type = MEM_HEAP;
      }
    
      return e;
    }
    

    ....speicher freigeben über etwa so eine funktion

    int free_ext (extended_charptr_t *e)
    {
      if (e->type == MEM_HEAP)
      {
        free (e->ptr);
        e->type = MEM_UNUSED;
        return 1;             // <-- OK
      }
      return 0;               // <-- falscher typ
    }
    

    die benutzung gestaltet sich dann folgendermassen:

    // zwei speicher blöcke anlegen
    extended_charptr_t a = from_heap (1000);
    extended_charptr_t b = from_other_source ("hello doof");
    
    // mach was mit dem speicher ...
    strcpy (a.ptr, "abcdef123456");
    puts (b.ptr);
    
    // und freigeben
    free_ext (&a);   // <-- ruft 'free' auf  
    free_ext (&b);   // <-- macht nix
    

    🙂


Anmelden zum Antworten