C清理错误/终止

时间:2014-11-20 22:50:05

标签: c memory

我按顺序运行了一堆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失败时,程序退出而不释放先前的程序。有哪些技术可以确保在出现故障的情况下,程序安全退出并释放所有已分配的内存?

5 个答案:

答案 0 :(得分:3)

大多数现代操作系统会在调用exit(...)后进程终止后释放正确的内存。这些操作系统包括:

  • 所有Unix变体,包括Linux和Mac OS X
  • 所有Windows版本
  • 所有DOS变种

答案 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->arrayfoo将相应地被释放。如果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);