简体   繁体   中英

Memory leak, while allocating a two dimensional game field

I am new to using Valgrind and have problems debugging the code, since it works except for what I assume are memory leaks on the marked line. Am I allocating the wrong size here?

Field *createField(unsigned int xsize, unsigned int ysize) {
    /* Alright! Let's start off by assigning an new field that we can return.*/

unsigned int i, j;
    Field *returnField;
    returnField = malloc(sizeof(Field));
    if(returnField == NULL) {
        return NULL;
    }

    returnField->xsize = xsize;
    returnField->ysize = ysize;
    returnField->cells = malloc(ysize * sizeof(State *)); // memory leaks?!
    if(returnField->cells == NULL) {
        free(returnField);
        return NULL;
    }
    /* Alright, now we have the y dimension pointer allocated. It's time
     * to move on to the x dimension*/

    for (j = 0; j < ysize; j++) {
        returnField->cells[j] = malloc(xsize * sizeof(State));
        if (returnField->cells[j] == NULL) {
            for (i = 0; i < j; i++) {
                free(returnField->cells[i]);
            }
            free(returnField);
            return NULL;
        }
        for (i = 0; i < xsize; i++) {
            returnField->cells[j][i] = DEAD;
        }
    }

    return returnField; 
}
/* Free memory allocated for field <f>.
 */
void releaseField(Field *f)
{
    unsigned int j;
    for (j = 0; j < f->ysize; j++) {

        free(f->cells[j]);
    }
    free(f);
}

Below is the header containing the structures:

typedef enum {
    DEAD,
    ALIVE
} State;

typedef struct {
    unsigned int xsize, ysize;
    State **cells;
} Field;

You allocate memory to hold the cell pointers:

returnField->cells = malloc(ysize * sizeof(State *));

But you never free that memory. You do free the individual cells, but never the cell pointer itself:

    if (returnField->cells[j] == NULL) {
        for (i = 0; i < j; i++) {
            free(returnField->cells[i]);
        }
        free(returnField->cells);
        // ^^ This was missing
        free(returnField);
        return NULL;
    }

The same problem appears in your releaseField() implementation. I'd even suggest making it robust against partial allocation:

/* Free memory allocated for field <f>.
 */
void releaseField(Field *f)
{
    unsigned int j;
    if (f != NULL) {
       if (f->cells != NULL) {
           for (j = 0; j < f->ysize; j++) {
               free(f->cells[j]);
           }
       }
       // free cell pointer array memory, too
       free(f->cells);
       free(f);
    }
}

Also replace returnField->cells = malloc(ysize * sizeof(State *)); by

returnField->cells = calloc(ysize, sizeof(State *));

Do the same thing when allocating the returnField struct itself and you can even use releaseField() for partially allocated fields and thus avoid code duplication:

returnField = calloc(1, sizeof(Field));

This way, you should be able to simply call releaseField() even when you only have a partially allocacted field structure.

This might not be the real problem but you are not deallocating the memory allocated for cells in this block.

    if (returnField->cells[j] == NULL) {
        for (i = 0; i < j; i++) {
            free(returnField->cells[i]);
        }

        // Need to deallocate returnField->cells
        // Add the following line.
        free(returnField->cells);

        free(returnField);
        return NULL;
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM