String literals und free() ?



  • Hi everyone

    In meinem momentanen Projekt existieren diverse Funktionen, welche ein Array von Strings übergeben haben möchten:

    argv = (char **) realloc(argv, sizeof(char *) * 3);
    argv[0] = (char *) malloc(sizeof(char) * 2);
    argv[0][0] = '5', argv[0][1] = '\0';
    argv[2] = (*this).get_strLpTimeStamp();
    // ...
    
    iStat = (*this).MsgSend(spReadIn, (*this).iR, argv, 3);
    for(int i = 0; i < 3; i++) {
       free(argv[i]);
    }
    free(argv);
    

    Ihr merkt schon, das wird sehr schnell ganz schön umständlich und besonders weil ich bei malloc() das unangenehme Talent besitze, den free() zu vergessen, gefällt mir die Lösung ganz und gar nicht 😉 .

    Statt dessen habe ich mir also das hier ausgedacht:

    char *strTmp = (*this).get_strLpTimeStamp();
    char *argv[] = { "5", "P.01", strTmp };
    free(strTmp);
    

    Tja, und jetzt die Preisfrage: Nach meinem Verständnis müssten diese Daten doch jetzt eigentlich auf dem Stack alloziiert worden sein, anstatt wie zuvor auf dem Heap. Also müsste ich mir doch

    for(int i = 0; i < 3; i++) {
       free(argv[i]);
    }
    free(argv);
    

    sparen können, nicht wahr?

    Thx für eure Hilfe und greeetz
    Kessi



  • Wenn du in der Lage bist, C++-Mittel zu nutzen, solltest du auf malloc/free komplett verzichten. Speichere dein "Array von Strings" lieber als std::vectorstd::string, da brauchst du dich nicht mehr um die Speicherverwaltung kümmern.

    Ansonsten: Ja, in deinem zweiten Beispiel liegt dein Array auf dem Stack (wo die einzelnen Array-Elemente hinzeigen, hängt vom Programm ab), also brauchst du sie nicht mehr freizugeben. Das schließt übrigens auch das free(strTemp); mit ein - das letzte Array-Element zeigt auf den selben Speicher wie strTemp (den get_LpTimeStamp() reserviert hat), und wenn du die Daten dort freigibst, zeigst du anschließend auf einen Müllhaufen.



  • Wie wäre es mit einer Hilfsklasse, die Dir die Arbeit abnimmt. So in etwa so:

    class ArgCreator
    {
        unsigned size;
        char** argv;
      public:
        explicit ArgCreator(unsigned size_);
        ~ArgCreator();
        void setArg(unsigned n, const char* str);
        unsigned getSize() const  { return size; }
        char** getArgv() const    { return argv; }
        operator char** () const  { return argv; } // das ist Geschmackssache
    };
    
    ArgCreator::ArgCreator(unsigned size_)
    { // TODO Allokation implementieren
    }
    
    ArgCreator::~ArgCreator()
    { // TODO Freigabe implementieren
    }
    
    void ArgCreator::setArg(unsigned n, const char* str)
    { // TODO Speicher allokieren und str kopieren
    }
    

    Eine Instanz der Klasse legst Du dann bei Bedarf auf den Stack. Der Destruktor wird dann automatisch aufgerufen.

    Tntnet


Anmelden zum Antworten