在 c 中的结构成员中间调用 free 时会发生什么?

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

我只是想知道今晚 free() 调用结构成员时发生了什么。 让我们看看下面的简单代码。

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;
}

免费制作崩溃。 但下一个代码运行良好。

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;
}

当然,我认为第二个会很好用,第一个也是不正确的代码。

我想知道的是第一次执行时发生了什么。 free() 释放 'a' 变量,结构的中间部分,而不是结构的地址。

he->a 未分配、动态分配且无法释放。 在这种情况下,he->c 内存地址为 00D2Ad50,he->a 为 00D2AD64。 struct 变量将由 malloc() 放置在堆中。 he->c 有相同的地址'he'。而he->c + 4*5就是he->a。 he->a 也在堆中?那么,在 free(he->a) 上会发生什么?

您的第一个示例是 undefined behavior。您尝试释放未从内存管理函数 (malloc) 获得的内容。就像未定义的行为意味着——它可能会崩溃、工作或任何东西——该行为不是由标准指定的。所以任何事情都可能发生。

来自§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

您的第二个示例不是未定义的行为并且是完全合法的 - 这已通过下面给出的引述得到验证。 来自 §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.

由于不涉及填充,因此第一个成员的地址必然是 return 由先前调用的 malloc 编辑的地址。根据前面提到的关于 free 的引述,这没问题。

另外要说明的一点是 - 不要转换 malloc 的 return 值并检查 malloc 的 return 值。

1.当您尝试从已分配对象的中间释放内存或使用内存管理函数根本没有分配内存时,就会违反此规定。int *a = malloc(sizeof*a * 5) 然后调用 free(&a[5]) 这将是未定义的行为甚至这个 int a[10]; 然后调用 free(&a[5]) 也是一个。对于动态分配,您始终可以使用 realloc 缩小分配的 space(释放不需要的内存。)