Search code examples
carraysdynamicstructfree

C Free Dynamic Array of Structs - Why are they not contigous


I'm struggling with a C struct which must hold a dynamic array of smaller structs:

typedef struct issueStruct {
    int data;
} issue;

typedef struct volumeStruct {
    issue* collection;
    size_t elements;
} volume;

I can dynamically create as many issue structs as I like within a volume struct's array. I can also iterate through that array:

int main(){
    volume* TimeMagazine = (volume*)malloc(sizeof(volume));
    TimeMagazine->collection = (issue*)malloc(4 * sizeof(issue));
    TimeMagazine->elements = 4;

    issue* ptr = TimeMagazine->collection;
    int i;

    // Populate & iterate through array:
    i = 0;
    while(i < TimeMagazine->elements){
            ptr->data = 100*i;
            printf("%d)  %d\n", i, ptr->data);
            i++;
            ptr = ptr+i;       // Advance ptr
    }
    return 0;
}

OUTPUT:
[Linux]$ gcc -Wall magazines.c
[Linux]$ ./a.out
0)  0
1)  100
2)  200
3)  300
[Linux]$

So far, so good. When I step through the above in GDB, everything looks okay, although I notice that the issue structs do not seem to have contiguous memory addresses. Here's the memory addresses I saw:

issue 0)  0x602030
issue 1)  0x602034
issue 2)  0x60203c
issue 3)  0x602048

That gave me some pause; I would have assumed all issues would be 4 bytes apart, as sizeof(issue) = 4. More seriously, when I modify my "iterate through" code to free up the elements of the array, my code seg faults. Specifically, it faults when it tries to free the second issue. Here's the code:

    i = 0;
    ptr = TimeMagazine->collection;
    issue* ptr2 = ptr;
    while(i< TimeMagazine->elements){
            printf("freeing %d...\n", i);
            i++;
            free(ptr2);           // free ptr2
            ptr2 = ptr = ptr+i;   // advance ptr & ptr2
    }

Here's the error (GCC on Linux):

*** Error in `./a.out': free(): invalid pointer: 0x000000000137c034 ***

So I'm sure I'm missing something here, but not sure what. Can someone recommend an effective way to free() the array elements?

Many thanks!

-Pete

PS - There are a lot of "freeing structs in array" posts, but none seemed to precisely match what I am doing. So I am posting this in the hope that my version of this question is unique.


Solution

  • while(i < TimeMagazine->elements){
            ptr->data = 100*i;
            printf("%d)  %d\n", i, ptr->data);
            i++;
            ptr = ptr+i;       // Advance ptr
    }
    

    You are using wrong pointer arithmetic in ptr = ptr+i, should be ptr = ptr+1 or you access outside of the bounds. Same for the free section.

    And as pointed out by @kaylum in comments: you are calling free in a loop, this is also wrong, you can free(TimeMagazine->collection); at once since you are reserving space for 4 elements in the same block.