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