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

Is it safe to use void ** when freeing double pointers of other types?

我通过以下方法在 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 ** 的使用存在问题。

There is no generic pointer-to-pointer type in C. void * acts as a generic pointer only because conversions (if necessary) are applied automatically when other pointer types are assigned to and from void *'s; these conversions cannot be performed if an attempt is made to indirect upon a void ** value which points at a pointer type other than void *. When you make use of a void ** pointer value (for instance, when you use the * operator to access the void * value to which the void ** points), the compiler has no way of knowing whether that void * value was once converted from some other pointer type. It must assume that it is nothing more than a void *; it cannot perform any implicit conversions.

In other words, any void ** value you play with must be the address of an actual void * value somewhere; casts like (void **)&dp, though they may shut the compiler up, are nonportable (and may not even do what you want; see also question 13.9). If the pointer that the void ** points to is not a void *, and if it has a different size or representation than a void *, then the compiler isn't going to be able to access it correctly.

但是,由于我没有取消对这个指针的引用,我不确定它是否有问题。有人可以解释它是否有问题,为什么?

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

这不仅会完全回避您当前的问题,还会为矩形(非锯齿状)二维数组提供卓越的性能,因为所有内存都是连续的,而不是分散 row/column。

没有。即使指针类型具有相同的大小和表示形式,除少数特殊情况外,C 也不允许不同类型别名,并且编译器可以并且将会假设这一点进行转换(优化)。如果你真的想要这样一个通用的自由循环,你可以把循环放在一个宏中,这个宏在它具有正确指针类型的上下文中(在调用者中)展开,但你真的应该避免 "deep" 伪二维数组