void **指针和void * []作为函数参数

时间:2016-01-26 14:58:20

标签: c arrays pointers casting void-pointers

我收到以下警告: incompatible pointer types 'void**' and 'int* [2]'

当我尝试编译以下代码时:

#include <stdlib.h>

void func1(void *arr[]) { }

int main() {
    int *arr[2];
    for (int i = 0; i < 5; i++) {
        arr[i] = (int*)malloc(sizeof(int));
        *(arr[i]) = 5;
    }
    func1(arr);
}

现在,当我使用(void**)投射arr时它会起作用,而我无法找到原因。此外,我发现我还需要使用以下代码:

#include <stdlib.h>

void func1(void **arr) { }

int main() {
    int **arr;
    int i[] = { 1, 2 };
    int j[] = { 3, 4 };
    *arr = i;
    *(arr+1) = j;
    func1(arr); //Doesn't compile unless I use (void*) or (void**) casting
}

我知道如果一个函数的参数是一个指向void的指针,我们可以传递给它,无论我们想要什么指针而不进行转换,因为所有指针都具有相同的大小,那么为什么我不能以相同的方式将指针传递给指针?

2 个答案:

答案 0 :(得分:4)

您的第二个代码段有几个问题:

void func1(void** arr) { }
int main() {
    int** arr;
    int i[] = {1,2};
    int j[] = {3,4};
    *arr = i;
    *(arr+1) = j;
    func1(arr); //Doesn't compile unless I use (void*) or (void**) casting
}

您永远不会将arr初始化为指向int的指针或指针数组。它是未初始化的,因此它的价值可以是任何东西。将*arr设置为i时,将调用未定义的行为。

此外,int **void **不是可互操作的类型,您无法隐式地将其中一个转换为另一个。其基本原理是,在某些罕见的系统中,int *void *可能具有不同的表示形式。将指向int *的指针作为指向void *的指针投射将与指向float的指针作为指向double的指针一样不正确。在表示相同的系统上,您可以编写显式强制转换。

以下是更正后的版本:

#include <stdlib.h>

void func1(void **arr) { }

int main(void) {
    int *int_pointer_array[2];
    int **arr = &int_pointer_array;
    int i[] = { 1, 2 };
    int j[] = { 3, 4 };
    *arr = i;     /* this line modifies int_pointer_array[0] */
    *(arr+1) = j; /* this line modifies int_pointer_array[1] */
    func1((void **)arr);
    return 0;
}

答案 1 :(得分:2)

所有对象指针类型(包括int *)都保证与void * 可互换,但它们不是可互换的。类型int *的表示不必与类型void *的表示相同(尽管在实践中,它几乎总是如此),因此没有从指针到{{1的自动转换(int *)指向int **的指针(即void *)。假设一种类型的指向式事物可以被正确地重新解释为另一种类型的事物是不安全的。

顺便提一下,请注意:

  

如果一个函数的参数是一个指向void的指针,我们可以传递给它,而不需要强制转换,因为所有指针的大小都相同

是一种错误的表征。指针所需的都必须具有相同的尺寸。只需将每个对象指针转换转换为void **并返回,并且这种往返转换的结果等于原始指针。

请注意@Lundin的评论:数组不是指针。然而,在大多数情况下,数组类型的值会衰减到指针,包括它们作为函数参数出现或作为赋值运算符的右手操作数。