我按顺序运行了一堆malloc
,并每次检查以确保它成功。像这样:
typedef struct {
int *aray;
char *string;
} mystruct;
mystruct *mystruct_init(int length)
{
mystruct *foo = malloc(sizeof(int *));
if (!foo) exit(1);
foo->array = malloc(length * sizeof(int));
if (!foo->array) exit(1);
foo->string = malloc(length * sizeof(char));
if (!foo->string) exit(1);
return foo;
}
因此当malloc
失败时,程序退出而不释放先前的程序。有哪些技术可以确保在出现故障的情况下,程序安全退出并释放所有已分配的内存?
答案 0 :(得分:3)
大多数现代操作系统会在调用exit(...)
后进程终止后释放正确的内存。这些操作系统包括:
答案 1 :(得分:2)
这是我最喜欢的技巧之一:
do {
a = malloc(...);
if (!a) break;
b = malloc(...);
if (!b) {
free(a);
break;
}
} while (0);
if (!a) {
...
return;
}
...
free(b);
free(a);
答案 2 :(得分:2)
如果您正在设计作为操作系统一部分运行的驱动程序,则需要更仔细地处理此问题。在这种情况下,经常使用goto
。例如
mystruct *mystruct_init(int length)
{
mystruct *foo = malloc(sizeof(int *));
if (!foo) goto FOO_FAIL;
foo->array = malloc(length * sizeof(int));
if (!foo->array) goto ARRAY_FAIL;
foo->string = malloc(length * sizeof(char));
if (!foo->string) goto STRING_FAIL;
return foo;
STRING_FAIL:
free(foo->array);
ARRAY_FAIL:
free(foo);
FOO_FAIL:
REPORT_ERROR; // user defined behavior
return NULL;
}
因此,如果foo->string
未成功分配,foo->array
和foo
将相应地被释放。如果foo->array
失败,则只会释放foo
。当其中任何一个失败时,该函数返回NULL,这允许调用者检查返回值并决定下一步。
答案 3 :(得分:1)
如果你想进行事后清理,那么你可以注册一个atexit处理程序
http://man7.org/linux/man-pages/man3/atexit.3.html
BTW我并不是说它很容易做(或更正)
答案 4 :(得分:0)
你也可以这样做,我认为它是最干净的方式,我经常使用它,但是从函数返回,而不是退出程序,因为系统是真的将在退出时释放记忆。
顺便说一句,你的程序会给出分段错误,因为你没有为foo
分配足够的空间。
typedef struct {
int *aray;
char *string;
} mystruct;
mystruct *mystruct_init(int length)
{
mystruct *foo = malloc(sizeof(mystruct)); // you need to allocate space for string too
if (!foo)
return NULL;
memset(foo, 0, sizeof(mystruct)); // initialize all members to NULL
foo->array = malloc(length * sizeof(int));
if (!foo->array)
goto abort;
foo->string = malloc(length * sizeof(char));
if (!foo->string)
goto abort;
return foo;
abort:
if (foo->array)
free(foo->array);
if (foo->string)
free(foo->string);
return NULL;
}
现在在调用函数中,您可以像
一样干净利落地完成mystruct *foo;
foo = mystruct_init(length /* assuming this is declared and set. */);
if (!foo)
exit(1);