释放其他类型的双指针时使用void **是否安全?

时间:2018-01-27 01:42:15

标签: c void-pointers

我通过以下方法在double int指针中实例化了一个二维数组。

int **make2Dint(int rows, int columns) {
    //a is our 2D array
    int **a = (int **)calloc(rows, sizeof(int *));
    //If we can't allocate the necessary memory, return null.
    if (!a) {
        return (int **)NULL;
    }

    //Allocate each row with the correct amount of column memory.
    for (int i = 0; i < rows; i++) {
        a[i] = (int *) calloc(columns, sizeof(int));
        //If we can't allocate the necessary memory, return null.
        if (!a[i]) {
            return (int **)NULL;
        }
    }

    return a;
}

为此,我还写了一个免费功能,如下所示

void free2DArray(void **a, int rows) {
    for (int i = 0; i < rows; i++) {
        free(a[i]);
    }

    free (a);
}

在使用我的免费功能时,(通过free2DArray(array, rows);然而,gcc给了我一个警告。

In file included from life.c:6:0:
twoD.h:14:6: note: expected ‘void **’ but argument is of type ‘int **’
 void free2DArray(void **a, int rows);
      ^~~~~~~~~~~

现在,我可以通过转换为void **来消除这种情况,但this似乎表明我对void **的使用存在问题。

  

C中没有通用的指向指针类型.void *仅作为通用指针使用,因为当其他指针类型分配给void *&void时,会自动应用转换(如果需要);如果尝试间接在指向void *之外的指针类型的void **值上,则无法执行这些转换。当您使用void **指针值时(例如,当您使用*运算符访问void **指向的void *值时),编译器无法知道该void *值是否为一次从其他指针类型转换而来。它必须假设它只不过是一个空洞*;它无法执行任何隐式转换。

     

换句话说,你玩的任何void **值必须是某个地方的实际void *值的地址;像(void **)&amp; dp这样的演员虽然可以关闭编译器,但是不可移植(甚至可能不能做你想做的事情;另见问题13.9)。如果void **指向的指针不是void *,并且如果它具有与void *不同的大小或表示,则编译器将无法正确访问它。

但是,由于我没有取消引用此指针,因此我不确定它是否存在问题。有人可以解释它是否有问题,为什么?

2 个答案:

答案 0 :(得分:2)

没有。即使指针类型具有相同的大小和表示,C也不允许使用不同类型的别名,除非在一些特殊情况下,编译器可以并且将进行转换(优化)。如果你真的想要这样一个通用的自由循环,你可以将循环放在一个宏中,该宏在具有正确指针类型的上下文中扩展(在调用者中),但你应该真的只是避免“深度”伪二维数组

答案 1 :(得分:1)

将二维数组创建为嵌套的一维数组是不好的做法。您应该只需一步分配整个空间,free()只需一次。

这不仅会完全回避您当前的问题,它还会为矩形(非锯齿状)2D阵列提供卓越的性能,因为所有内存都是连续的,而不是按行/列分散。