简体   繁体   中英

C malloc error freeing struct

I've just re-start learning C, but i'm really confused with some memory management details. I'm getting

pointer being freed was not allocated ... Abort trap

for the code below. Do i really need 1 free per malloc? Why my code is wrong?
Thanks!

#define N 9

typedef struct
{
  int MAX_LIST_SIZE;
  int length;
  int *ini;
}List;

/* allocates new List and its data */
List *newList(int size)
{
    List *list = malloc(sizeof(List));
    list->MAX_LIST_SIZE = size;
    list->length = 0;
    list->ini = malloc(sizeof(int) * size);

    return list;
}

/* add some value to the list */
void addList(List *list, int val)
{
    if (list->length < list->MAX_LIST_SIZE)
        list->ini[list->length++] = val;
    else
        fprintf(stderr, "Error: add(): List is full.\n");
}

/* get an array of N*N lists malloc-ed Lists */
List *gridList()
{
    int i, j;
    List *cells = malloc(sizeof(List) * N * N);

    for (i = 0; i < N * N; i++)
    {
      /* malloc is called inside NewList()*/
      cells[i] = *newList(N);
      for (j = 0; j < N; j++)
          addList(&cells[i], j + 1);
    }

    return cells;
}


/* inside main */
List *cells = gridList();

/* use cells ... */

/* free */
for (i = 0; i < N * N;  i++)
{
    free(cells[i].ini);
    /* line below causes CRASH */
    free(&cells[i]);
}

You do :

cells[i] = *newList(N);

which sets each element in cells to a copy of the list dynamically allocated by newList . So newList dynamically allocates a list, then you take the pointer to that dynamically allocated List , dereference it, and copy it into cells[i] . So then later on when you go to free() each element:

free(&cells[i]);

It doesn't work because each element in cells[i] is a List , not a List * (list pointer) allocated by malloc() .

So you have two options. One (bad one) is to just remove that last free() line since there's nothing to free. However, this just covers up a larger problem which is that you now have memory leaks because you can't go back and free the dynamically allocated List s created with newList() .

Instead it's likely you want to have an array of pointers to the lists, which you can do by changing it to:

List **cells = malloc(sizeof(List*) * N * N);

so that cells[i] refers to a List * . newList() returns such a pointer, so you would change that line to:

cells[i] = newList(N);

similarly, addList() takes such a pointer, so you'd simply change that line to:

addList(cells[i], j + 1);

since &cells[i] would pass it the address of the pointer, which is not what you want.

Finally, change the free statements to:

free(cells[i]->ini); // ->init because cells[i] is now a pointer to a List, List *
free(cells[i]);

The problem is you are allocating an array of lists, copying the full contents of your lists into the array elements, and then trying to free them. The original allocated List records are a memory leak, and the free calls are indeed trying to free memory that was not malloc'ed (or more exactly were malloc'ed in a single big block).

You want an array of pointers to pointers to hold your lists:

/* get an array of N*N lists malloc-ed Lists */
List **gridList()
{
    int i, j;
    // VV note change here
    List **cells = malloc(sizeof(List*) * N * N); 

    for (i = 0; i < N * N; i++)
    {
        /* malloc is called inside NewList()*/
        cells[i] = newList(N); // << Note change here.
        for (j = 0; j < N; j++)
            addList(cells[i], j + 1);
    }
    return cells;
}

/* free */
for (i = 0; i < N * N;  i++)
{
    free(cells[i]->ini); // << and here
    /* line below causes CRASH */
    free(cells[i]); // << and here
}
free(cells);

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