-1

構造体を解放するメソッドを作成しました。今、私は問題を抱えています。このメソッドを 2 回呼び出すと、エラーが発生します。しかし、構造体に何かがあるかどうかを確認するので、エラーが発生する可能性があるかどうかはわかりません。

私の構造体:

typedef struct {
    int num_rows;
    int num_cols;
    int** data;
} matrix;

私の無料の方法:

void free_matrix(matrix* m){
    int i;
    for(i=0;i<m->num_rows;i++){
        if(m->data[i]!=NULL){
            free(m->data[i]);
        }
    }
    if(m->data!=NULL){
        free(m->data);
    }
}

追加の方法:

void fill_matrix_a(matrix* m){
    m->data[0][0] = 1;
    m->data[0][1] = 0;
    m->data[0][2] = 2;
    m->data[1][0] = 0;
    m->data[1][1] = 3;
    m->data[1][2] = 1;
}

void fill_matrix_b(matrix* m){
    m->data[0][0] = 0;
    m->data[0][1] = 3;
    m->data[1][0] = 2;
    m->data[1][1] = 1;
    m->data[2][0] = 0;
    m->data[2][1] = 4;
}

void init_matrix(matrix* m, int num_rows, int num_cols){
    int i;
    m->num_cols = num_cols;
    m->num_rows = num_rows;
    m->data = (int**) calloc(num_rows,sizeof(int*));
    if(m->data==NULL){
        printf("%s\n", "ERROR: probleem bij geheugenallocatie.");
        exit(1);
    }
    for(i=0;i<num_rows;i++){
        m->data[i] = (int*) calloc(num_cols,sizeof(int));
        if(m->data[i]==NULL){           /* THE PROGRAM SAYS THIS IS TRUE BUT IT ISN'T BECAUSE I ALREADY FREED THE DATA OF B!! */
            printf("%s\n", "ERROR: probleem bij geheugenallocatie.");
            exit(1);
        }
    }
}

私にエラーを与える方法:

void ex_1_matrix_operations(){
    matrix a,b,c;

    /* init a(2,3) and fill with elements */
    init_matrix(&a,2,3);
    fill_matrix_a(&a);
    print_matrix(&a);

    /* init b (default) and fill with elements */
    init_matrix_default(&b);
    fill_matrix_b(&b);
    print_matrix(&b);
    free_matrix(&a);
    free_matrix(&b);

    /* create unity matrix */
    init_identity_matrix(&a,2);
    print_matrix(&a);
    free_matrix(&a);
    free_matrix(&b); /* THIS IS WHERE MY ERROR OCCURS*/
}
4

2 に答える 2

9

free_matrixに対して2 回、 に対して 2 回a呼び出していますba最初にメモリを割り当ててから解放するため、この順序でこれらの操作を 2 回実行します。ただし、b割り当ててから解放し、再度割り当てずに解放しようとすると、クラッシュにつながります。

割り当てられたメモリを解放するために呼び出すfreeと、それを指すポインタが に設定されませんNULL。これは手動で行う必要があります。これを行わないと、ポインターはダングリング ポインター、つまり、プロセスが読み取り (アクセス) できない場所を指すポインターになります。これを回避するために、ヘルパー関数を使用してメモリを解放し、ポインターを に設定することは珍しくありませんNULL

void free_data(void **pp)
{
    if (pp && *pp)
    {
       free(*pp);
       *pp = NULL;
    }
}

ポインターが null でないかどうかを確認することは完全に有効ですが、ポインターを逆参照することは、言語の観点からは未定義の動作 (UB) です。呼び出すfreeと、C ランタイム ライブラリにそれを実行するように求められるため、言語仕様に従って UB ランドに入ります。C ランタイムに関しては、プロセスによって所有されなくなったメモリにアクセスしようとするため、オペレーティング システムが何らかの形式のアクセス拒否エラーを発生させるため、クラッシュします。たとえば、Linux はこれを (とりわけ) Segmentation Faultと呼びますが、Windows Access Violationと言います。

余談ですが、解放されたポインターを に設定することNULLは、二重削除のバグが発見されないようにするため、良い習慣ではないと主張する人もいます。解放されたポインターを に設定しNULL、他の場所でfree同じポインターを呼び出すとします。つまり、基本的に を呼び出しますfree(NULL);。これは渡すのに有効なパラメーターでfreeあり、何もしないため、二重削除が発生したことを世界に知らせることはできません。に設定されていない場合NULL、 への 2 回目の呼び出しでfree、既に解放されている場所を解放しようとするとアクセス違反エラーが発生し、二重削除のバグが知られるようになります。

于 2014-10-20T13:36:18.077 に答える
2

free() はポインターを NULL に設定しません。あなたはそれを自分で行う必要があります。

于 2014-10-20T13:36:08.720 に答える