简体   繁体   中英

What happen when call free on middle of struct's member in c?

I just wonder what's happen when free() called about member of struct tonight. Let see below simple code in c.

typedef struct {
    int c[5];
    int a[10];
    int *b;
}stma;
int main() {
    stma *he = (stma*)malloc(sizeof(stma));
    int *ac = he->a;
    free(ac); //This point is crash.
    return 0;
}

The free make crash. But next code is work well.

typedef struct {
    int c[5];
    int a[10];
    int *b;
}stma;
int main() {
    stma *he = (stma*)malloc(sizeof(stma));
    int *ac = he->c; //This point is changed.
    free(ac); //Work well.
    return 0;
}

Of course, I could think second will work well and first is not correct code too.

What I wonder is what is happen during first execution. free() free 'a' variable, the middle of struct, not address of struct.

he->a is not malloced, dynamically assigned and couldn't be free. In this case, he->c memory address is 00D2Ad50 and he->a is 00D2AD64. The struct variable will be placed in heap by malloc(). he->c have same address of 'he'. And he->c + 4*5 is he->a. he->a is also in heap? Then, what happen on free(he->a)?

The first of your examples is undefined behavior . You try to free what you didn't get from a memory management function ( malloc ). And like undefined behavior means - it may crash, work or anything - the behavior is not specified by the standard. So anything may happen.

From § 7.22.3.3 ¶2

Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined. 1

Your second example is not undefined behavior and is perfectly legal - this is validated by the quote given below. From § 6.7.2.1 ¶15 N1570

Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.

As there is no padding involved then the address of the first member is necessarily the one returned by the malloc previously called. By the quote previously mentioned about free this is alright.

Also another point to be made is - not casting the return value of malloc and checking the return value of malloc .

1. One violation of this would when you try to free memory from the middle of the allocated object or something you didn't allocate at all using memory management function. int *a = malloc(sizeof*a * 5) and then calling free(&a[5]) this will be undefined behavior or even this int a[10]; and then calling free(&a[5]) would be one. For dynamic allocation, you can always shrink the allocated space using realloc (freeing the memory that is not needed.)

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