I'm getting the following warning:
incompatible pointer types 'void**' and 'int* [2]'
.
When I try to compile the following code:
#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);
}
Now, it works when I cast arr with (void**)
, and I couldn't find a reason for that. Furthermore I found that I also need to cast in the following code:
#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
}
I know that if a function's parameter is a pointer to void
we can pass to it whatever pointer we want without casting because all pointers are of the same size then why can't I pass a pointer to a pointer the same way?
There are several problems with your second code snippet:
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
}
You never initialize arr
to point to a pointer or an array of pointers to int
. It is uninitialized, so its value can be anything. When you set *arr
to i
, you invoke undefined behavior.
Furthermore, int **
and void **
are not interoperable types, you cannot convert one to the other implicitly. The rationale for this is that on some rare systems, int *
and void *
may have a different representation. Casting a pointer to int *
as a pointer to void *
would be as incorrect as casting a pointer to float
as a pointer to double
. On systems where the representation is the same, you can just write the explicit cast.
Here is a corrected version:
#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;
}
All object pointer types, including int *
, are guaranteed to be interconvertible with void *
, but they are not interchangeable. The representation of type int *
does not have to be the same as the representation of type void *
(though in practice, it almost always is), so there is no automatic conversion from a pointer to int *
(i.e. int **
) to a pointer to void *
(i.e. void **
). It is not safe to assume that a pointed-to thing of one type can be correctly re-interpreted as a thing of the other pointed-to type.
Note, by the way, that this:
if a function's parameter is a pointer to void we can pass to it whatever pointer we want without casting because all pointers are of the same size
is an incorrect characterization. Pointers are not required to all be the same size. It is required only that every object pointer can be converted to type void *
and back, and that the result of such a round-trip conversion is equal to the original pointer.
Do take @Lundin's comments to heart: arrays are not pointers. Nevertheless, values of array type do decay to pointers under most circumstances, including when they appear as function arguments or as the right-hand operand of an assignment operator.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With