在哪里释放多个 malloc
Where to free multiple mallocs
我有如下一段代码:
void f(size_t n) {
int *a = malloc(n * sizeof *a);
if(a == NULL) {
report_error_and_exit();
}
int *b = malloc(n * sizeof *a);
if(b == NULL) {
free(a);
report_error_and_exit();
}
int *c = malloc(n * sizeof *a);
if(c == NULL) {
free(a);
free(b);
report_error_and_exit();
}
/*use a, b, c*/
}
或类似的东西。基本上,我需要多个 malloc
,并且它们都不能失败。
我想知道我应该在哪里释放 一些 分配的内存。随着函数变得越来越大,检查 malloc
失败变得更加混乱。
我考虑的一个可能的解决方案是执行如下操作:
void f(size_t n) {
int *a = malloc(n * sizeof *a);
if(a == NULL) {
goto malloc_fail;
}
/*...*/
malloc_fail:
free(a);
free(b);
/*...*/
report_error_and_exit();
}
但是不鼓励使用 goto
。
我想知道什么是合适的解决方案。
这实际上是在 C 中正确使用 goto
的经典示例。
虽然可以滥用 goto
(而且很严重),但其中一种确实有意义的情况是在错误处理代码中,例如这样。它只会向前跳转,使代码更易于阅读,并将所有错误处理放在一个地方,因此不易出错。
然而,您必须注意的一件事是,如果您跳过变量的初始化,则该变量未初始化。在您的示例中,如果第一次调用 malloc
初始化 a
失败,那么您当前编写的代码将在 b
和 c
上调用 free
未初始化。
这可以通过为每个失败设置不同的跳转目的地并以相反的顺序进行清理来解决。
void f(size_t n) {
int success = 0;
int *a = malloc(n * sizeof *a);
if(a == NULL) {
goto malloc_fail_a;
}
int *b = malloc(n * sizeof *b);
if(b == NULL) {
goto malloc_fail_b;
}
int *c = malloc(n * sizeof *c);
if(c == NULL) {
goto malloc_fail_c;
}
/*...*/
success = 1;
malloc_fail_c:
free(c);
malloc_fail_b:
free(b);
malloc_fail_a:
free(a);
if (!success) {
report_error_and_exit();
}
}
另一种方法是使用包装函数,例如:
void f()
{
int *a = malloc(n * sizeof *a);
int *b = malloc(n2 * sizeof *b);
int *c = malloc(n3 * sizeof *c);
bool success = a && b && c;
if ( success )
do_stuff(a, b, c);
free(c);
free(b);
free(a);
if ( !success )
report_error_and_exit();
}
我有如下一段代码:
void f(size_t n) {
int *a = malloc(n * sizeof *a);
if(a == NULL) {
report_error_and_exit();
}
int *b = malloc(n * sizeof *a);
if(b == NULL) {
free(a);
report_error_and_exit();
}
int *c = malloc(n * sizeof *a);
if(c == NULL) {
free(a);
free(b);
report_error_and_exit();
}
/*use a, b, c*/
}
或类似的东西。基本上,我需要多个 malloc
,并且它们都不能失败。
我想知道我应该在哪里释放 一些 分配的内存。随着函数变得越来越大,检查 malloc
失败变得更加混乱。
我考虑的一个可能的解决方案是执行如下操作:
void f(size_t n) {
int *a = malloc(n * sizeof *a);
if(a == NULL) {
goto malloc_fail;
}
/*...*/
malloc_fail:
free(a);
free(b);
/*...*/
report_error_and_exit();
}
但是不鼓励使用 goto
。
我想知道什么是合适的解决方案。
这实际上是在 C 中正确使用 goto
的经典示例。
虽然可以滥用 goto
(而且很严重),但其中一种确实有意义的情况是在错误处理代码中,例如这样。它只会向前跳转,使代码更易于阅读,并将所有错误处理放在一个地方,因此不易出错。
然而,您必须注意的一件事是,如果您跳过变量的初始化,则该变量未初始化。在您的示例中,如果第一次调用 malloc
初始化 a
失败,那么您当前编写的代码将在 b
和 c
上调用 free
未初始化。
这可以通过为每个失败设置不同的跳转目的地并以相反的顺序进行清理来解决。
void f(size_t n) {
int success = 0;
int *a = malloc(n * sizeof *a);
if(a == NULL) {
goto malloc_fail_a;
}
int *b = malloc(n * sizeof *b);
if(b == NULL) {
goto malloc_fail_b;
}
int *c = malloc(n * sizeof *c);
if(c == NULL) {
goto malloc_fail_c;
}
/*...*/
success = 1;
malloc_fail_c:
free(c);
malloc_fail_b:
free(b);
malloc_fail_a:
free(a);
if (!success) {
report_error_and_exit();
}
}
另一种方法是使用包装函数,例如:
void f()
{
int *a = malloc(n * sizeof *a);
int *b = malloc(n2 * sizeof *b);
int *c = malloc(n3 * sizeof *c);
bool success = a && b && c;
if ( success )
do_stuff(a, b, c);
free(c);
free(b);
free(a);
if ( !success )
report_error_and_exit();
}