Speicherleckfrei?



  • Bisher habe ich nur pures C++ geschrieben und als ich jetzt auf C (89 gezwungener maßen) wechseln muss für ein Projekt habe ich mich doch etwas erschrocken, was ich alles gar nicht mehr machen kann, aber das ist jetzt nebensächlich.
    Ich habe eine 2D Matrix, dessen Größe erst zur Laufzeit bekannt ist.
    Ich spare mir daraus einen echten 2D Array zu machen und berechne einfach die korrekten Indices.

    Da ich vorher mich nie wirklich selbst um Speicherreservierung und Freigebung kümmern musste, weiß ich jetzt gar nicht, ob das auch sauber alles wieder freigibt.
    EDIT: Ob das überhaupt stimmt!

    (btw: falls dieser Create, Destroy Ansatz Banane ist, will ich das natürlich auch wissen.)

    typedef struct {
        unsigned int width;
        unsigned int height;
        cm_data_t* data;
    } cm_matrix;
    
    cm_matrix* CreateMatrix(int width, int height);
    void DestroyMatrix(cm_matrix* m);
    
    cm_matrix* CreateMatrix(int width, int height) {
        cm_matrix* ret = malloc (sizeof *ret);
        ret->data = malloc (width * height * sizeof *ret->data);
        ret->width = width;
        ret->height = height;
        return ret;
    }
    void DestroyMatrix(cm_matrix* m) {
        free(m->data);
        free(m);
    }
    


  • cm_matrix* ret = malloc (sizeof *ret);
    

    Muss nicht dynamisch angelegt werden, deine paar Bytes kannst du auch ueber den Stack zurueckgeben. Aber prinzipiell kann das so gemacht werden wie du zeigst. Leider kann der Aufruf fehlschlagen und nachfolgende Zeilen wuerden einen nichtinitialisierten Yeiger dereferenzieren.

    Ich wuerde noch eine Testfunktion anbieten, die nachschaut, ob cm_matrix gueltig ist. Es kann sein, dass du angeforderten Speicher nicht bekommst.



  • main.c

    #include "matrix.h"
    
    int main(){
        cm_matrix *m = CreateMatrix(4,3);
        if(m)
            DestroyMatrix(m);
    }
    

    matrix.h

    #pragma once
    
    typedef struct cm_matrix cm_matrix;
    cm_matrix* CreateMatrix(unsigned int width, unsigned int height);
    void DestroyMatrix(cm_matrix *m);
    

    matrix.c

    #include "matrix.h"
    #include <stdlib.h>
    
    struct cm_matrix{
      unsigned int width, height;
      unsigned char *data;
    };
    
    cm_matrix* CreateMatrix(unsigned int width, unsigned int height){
        cm_matrix *m = (cm_matrix*)malloc(sizeof(*m));
        if(!m)
            return 0;
        m->data = (unsigned char*)malloc(width * height * sizeof(*m->data));
        if(!m->data){
            free(m);
            return 0;
        }
        m->width = width;
        m->height = height;
        return m;
    }
    
    void DestroyMatrix(cm_matrix *m){
        if(m){
            free(m->data);
            free(m);
        }
    }
    

    Auf diese Weise haben deine Matrizen einen Typnamen, jedoch ist der Inhalt verborgen und wird nur durch die Funktionen in matrix.c zugreifbar sein.
    Die Erstellung einer Matrix ist auch sicher und der Rückgabewert gibt Aufschluss, ob sie erfolgreich war.



  • Youka schrieb:

    ...

    Vom Prinzip richtig, nur solltest du den Cast weglassen, braucht man in C nicht.
    Und free kommt wunderbar mit NULL klar, die beiden ifs brauchst du also auch ncith (btw: wieso zwei? entweder es wird in der Funktion geprüft oder außerhalb).


  • Mod

    Nathan schrieb:

    Und free kommt wunderbar mit NULL klar, die beiden ifs brauchst du also auch ncith (btw: wieso zwei? entweder es wird in der Funktion geprüft oder außerhalb).

    Das if in Zeile 24 ist wichtig, das kannst du nicht weglassen. Ebenso das in Zeile 14. Hier liegt schließlich eine verschachtelte Struktur vor, da das Objekt selbst ebenfalls dynamisch erstellt wurde. Da muss daher geprüft werden, ob es tatsächlich existiert, bevor man auf die Innereien zugreift.

    Das if vor dem DestroyMatrix würde ich eher als allgemeines if sehen, dass prüft, ob man überhaupt ein Objekt bekommen hat:

    cm_matrix *m = CreateMatrix(4,3);
       if(m)
       {
          // arbeiten mit der Matrix
          DestroyMatrix(m);
       }
    


  • SeppJ schrieb:

    Nathan schrieb:

    Und free kommt wunderbar mit NULL klar, die beiden ifs brauchst du also auch ncith (btw: wieso zwei? entweder es wird in der Funktion geprüft oder außerhalb).

    Das if in Zeile 24 ist wichtig, das kannst du nicht weglassen. Ebenso das in Zeile 14. Hier liegt schließlich eine verschachtelte Struktur vor, da das Objekt selbst ebenfalls dynamisch erstellt wurde. Da muss daher geprüft werden, ob es tatsächlich existiert, bevor man auf die Innereien zugreift.

    Ups. Da war ich wohl doch zu schnell.
    Sorry, Youka.


Anmelden zum Antworten