-1

我写了一个方法来释放我的结构。现在我有一个问题。当我两次调用此方法时,它给了我一个错误。但是我确实检查了我的结构中是否有某些东西,所以我不知道它怎么可能给我错误。

我的结构:

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两次 fora和两次 for b。因为a你先分配内存然后释放它,按照这个顺序你做了两次这些操作;但是,因为b您分配然后释放,然后没有再次分配,您尝试释放,这会导致崩溃。

调用free释放分配的内存,不会将指向它的指针设置为NULL,这必须手动完成。如果不这样做,指针就会变成悬空指针,即指向进程不可读(可访问)的某个位置的指针。为了避免这种情况,有一个帮助函数来释放内存并将指针设置为NULL.

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

尽管检查指针是否为非空是完全有效的,但从语言的角度来看,取消引用它是未定义的行为 (UB)。调用free会要求 C 运行时库尝试这样做,从而根据语言规范输入 UB 域;至于 C 运行时,它将尝试访问不再由进程拥有的内存并因此崩溃,因为操作系统会引发某种形式的拒绝访问错误,例如 Linux 将调用此(以及其他)分段错误,而 Windows 会说访问冲突

顺便说一句,有些人认为设置一个释放的指针NULL不是一个好习惯,因为它掩盖了双重删除错误。假设您将释放的指针设置为NULL您调用的其他位置free,即您实际上会调用free(NULL);. 这是传递给的有效参数free,它什么也不做,因此永远不知道让世界知道刚刚发生了双重删除。如果未将其设置为NULL,则在尝试释放已释放的位置时,第二次调用free将引发访问冲突错误,从而导致已知的双重删除错误。

于 2014-10-20T13:36:18.077 回答
2

free() 不会将指针设置为 NULL。你需要自己做。

于 2014-10-20T13:36:08.720 回答