我只是想知道今晚free()调用struct成员时会发生什么。 让我们看一下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;
}
免费制造崩溃。 但是下一个代码运行良好。
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;
}
当然,我认为第二种方法效果很好,第一种方法也不正确。
我想知道首次执行时会发生什么。免费()免费' a'变量,struct的中间,不是struct的地址。
he-> a未被malloced,动态分配且无法自由。 在这种情况下,he-> c存储器地址是00D2Ad50并且he-> a是00D2AD64。 struct变量将由malloc()放在堆中。他> c具有相同的地址' he'。并且他 - > c + 4 * 5是he-> a。他 - > a也在堆里?然后,在free(he-> a)上会发生什么?
答案 0 :(得分:6)
您的第一个示例是undefined behavior。您试图释放您从内存管理功能(malloc
)获得的内容。并且像未定义的行为意味着 - 它可能崩溃,工作或任何事情 - 标准不指定行为。所以任何事情都可能发生。
来自§7.22.3.3¶2
否则,如果参数与先前由内存管理函数返回的指针不匹配,或者如果通过调用free或realloc释放了空间,则行为未定义。 1 < / p>
您的第二个示例不是未定义的行为,并且完全合法 - 这可以通过下面给出的引用进行验证。 来自§6.7.2.1¶15c11 N1570
在结构对象中,非位字段成员和位字段所在的单元具有按声明顺序增加的地址。指向结构对象的指针,适当转换,指向其初始成员(或者如果该成员是位字段,则指向它所在的单位),反之亦然。 结构对象中可能有未命名的填充,但不在其开头。
由于没有涉及填充,因此第一个成员的地址必然是之前调用的malloc
返回的地址。通过前面提到的关于free
的引用,这没关系。
还有一点要做 - 不要强制转换malloc
的返回值并检查malloc
的返回值。
<子> 1。当您尝试从分配的对象的中间释放内存或者根本没有使用内存管理功能分配内存时,会违反这一点。int *a = malloc(sizeof*a * 5)
然后调用free(&a[5])
这将是未定义的行为甚至这个int a[10];
然后调用free(&a[5])
就是一个。对于动态分配,您始终可以使用realloc
缩小分配的空间(释放不需要的内存。)