C 释放检查不起作用

标签 c free dynamic-memory-allocation dangling-pointer

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

我的结构:

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*/
}

最佳答案

您为 a 调用了两次 free_matrix,为 b 调用了两次。对于a,您首先分配内存,然后释放它,按照这个顺序,您执行这些操作两次;然而,对于b,您先分配然后释放,然后在不再次分配的情况下尝试释放,这会导致崩溃。

调用free来释放分配的内存,不会将指向它的指针设置为NULL,这必须手动完成。如果不这样做,指针就会变成 dangling pointer即指向进程无法读取(不可访问)的某个位置的指针。为了避免这种情况,使用辅助函数来释放内存并将指针设置为 NULL 的情况并不罕见。

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

虽然检查指针是否非空是完全有效的,但从语言的角度来看,取消引用它是未定义的行为(UB)。调用free会要求C运行时库尝试执行此操作,从而根据语言规范进入UB区域;对于 C 运行时,它将尝试访问不再属于进程的内存,从而崩溃,因为操作系统会引发某种形式的访问被拒绝错误,例如Linux 会将此称为(以及其他)Segmentation Fault ,而 Windows 会显示访问冲突

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

关于C 释放检查不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26466940/

相关文章:

c - 如何使用 ICMPv6 套接字接收 vlan header /l2 header

c - 编译器如何为变量分配内存地址?

c - 令人困惑的行为,malloc 和 free(),以及 libuv

c++ - 免费(指针)方法的性能?

c++ - 在 c++ 中创建父类(super class)类型的数组以动态存储子类对象

c - 动态内存分配和指针相关概念疑惑

c - 为什么puts()最后会打印一个额外的字符?

c - 抑制 "gcc -E"预处理代码输出中的注释

c - C 中的 Malloc 复制先前分配的字符串?

c - 尝试分配连续的内存块并使用 3 个索引访问它,但我的方法出现段错误