-1

このプログラムを考えてみましょう:

int main(void)
{
    int* i = malloc(sizeof(int));
    int* j = malloc(sizeof(int));
}

mallocただし、失敗する可能性があり、ポインターが作成されないため、これは単純なアプローチfreeです。

だからあなたはこれを行うことができます:

int main(void)
{
    int* i; 
    int* j;

    if ((i = malloc(sizeof(int)) < 0)
    {
        return -1;
    }
    if ((j = malloc(sizeof(int)) < 0)
    {
        free(i);
        return -1;
    }

    free(i);
    free(j);
}

ただし、これは非常にエラーが発生しやすいと思います。20 個のポインターを割り当てる必要があると考えてください。最後のmallocエラーの場合、free19 個の変数とreturn -1.

も知ってatexitいます。これは、次のように書くのに役立ちます。

int* i; 
int* j;

void del_i(void)
{
    free(i);
}

void del_j(void)
{
    free(j);
}

int main(void)
{
    if ((i = malloc(sizeof(int)) < 0)
    {
        return -1;
    }
    else
    {
        atexit(del_i);
    }

    if ((j = malloc(sizeof(int)) < 0)
    {
        return -1;
    }
    else
    {
        atexit(del_j);
    }
}

どちらの方が良いですが、すべてのポインターをグローバルとして宣言する必要はありません。基本的に、これら2つのアプローチを組み合わせる方法はありますか:

  1. ポインタのデストラクタを持ち、直接実行するか、atexit.
  2. 関数にローカルなポインタを持つ。
4

6 に答える 6

4

freeonNULLは、安全なノーオペレーションとして定義されています。したがって、ジャンプしないバリエーションは次のようになります。

int *i = malloc(sizeof(int)); 
int *j = malloc(sizeof(int));

if(i && j)
{
    // do some work
}

free(i);
free(j);
于 2016-03-24T16:02:28.127 に答える
3

まず、これは障害を検出しません。malloc

if ((i = malloc(sizeof(int)) < 0)
{
    return -1;
}

mallocNULL負の数ではなく、失敗時に戻ります。

次に、atexit静的オブジェクトとグローバル オブジェクトのクリーンアップに適しています。内部で使用するためだけにローカル オブジェクトをグローバルにするのは得策ではありませんatexit

より良いアプローチはstruct、全か無かの単位で割り当てる必要がある関連するすべてのポインターを作成し、それらを一度にすべて解放する関数を定義し、それぞれのメモリ チェックを使用してそれらを 1 つずつ割り当てる関数を作成することです。割り当て:

typedef struct AllOrNothing {
    double *dPtr;
    int *iPtr;
    float *fPtr;
    size_t n;
} AllOrNothing;

void freeAllOrNothing(AllOrNothing *ptr) {
    free(ptr->dPtr);
    free(ptr->iPtr);
    free(ptr->fPtr);
    free(ptr);
}

int allocateAllOrNothing(size_t n, AllOrNothing **res) {
    *res = malloc(sizeof(AllOrNothing));
    if (*res == NULL) {
        return -1;
    }
    // Freeing NULL is allowed by the standard.
    // Set all pointers to NULL upfront, so we can free them
    // regardless of the stage at which the allocation fails
    (*res)->dPtr = NULL;
    (*res)->iPtr = NULL;
    (*res)->fPtr = NULL;
    (*res)->n = n;
    (*res)->dPtr = malloc(n*sizeof(double));
    if ((*res)->dPtr == NULL) {
        free(*res);
        *res = NULL;
        return -1;
    }
    (*res)->fPtr = malloc(n*sizeof(float));
    if ((*res)->fPtr == NULL) {
        free(*res);
        *res = NULL;
        return -1;
    }
    (*res)->iPtr = malloc(n*sizeof(int));
    if ((*res)->iPtr == NULL) {
        free(*res);
        *res = NULL;
        return -1;
    }
    return 0;
}
于 2016-03-24T15:54:16.383 に答える
0

複数の出口点を避ける。インターレース割り当てとエラー処理を避けます。クリーンな操作順序に従います。

  1. リソースを宣言、割り当て、初期化します。
  2. すべて成功したら、タスクを実行します。
  3. 掃除。
  4. ステータスを返します。

 // Do all allocations first, test their `NULL`-ness, then free them all.
 int main(void) {
    // Allocate resources   
    // declare and allocate in one step
    int* i    = malloc(sizeof *i);
    double* j = malloc(sizeof *j);

    // Test for acceptability
    bool ok = i && j;

    // Perform the main body of code
    if (ok) {
      ; // do normal process in the code;
    }

    // free resources
    free(i);
    free(j);

    // return status
    return ok ? 0 : -1;
}
于 2016-03-24T19:20:31.253 に答える
0
int main(void)
{
    int* i = NULL; 
    int* j = NULL;
    bool success = false;

    do {
        i = malloc(sizeof(int));
        if (NULL == i) break;

        j = malloc(sizeof(int));
        if (NULL == j) break;

        success = true;
    } while (0);

    if (!success)
    {
        printf("Something failed!");
    }
    else
    {
        printf("All succeeded!");
        // Do more work
    }

    free(i);
    free(j);
    return (success? 0 : 1);
}
于 2016-03-24T16:06:33.400 に答える
0
int main(void)
{
int* i = NULL; // Init with NULL otherwise free on none NULL possible
int* j = NULLL;

if (!(i = malloc(sizeof(int)))
{
    goto exit;
}
if (!(j = malloc(sizeof(int)))
{
    goto exit;
}
...
exit:
    free(i);
    free(j);
    ...
    return err;
}

これは、goto ステートメントで解決できるものです。

于 2016-03-24T15:53:32.307 に答える
-1
    int *i=NULL,*j=NULL;

    if(!(i=malloc(sizeof(int))))
            goto EXIT;
    if(!(j=malloc(sizeof(int))))
            goto EXIT;
    /* do some work */
    return 0;
    EXIT:
            free(i);
            free(j);
            exit(EXIT_FAILURE);

goto は悪いプログラミング手法と見なされていますが、ここでは goto を使用してタスクを簡単かつシンプルに完了できます。

于 2016-03-24T16:30:59.703 に答える