What is the deference between passing array this way:
static char arr[N];
void func(void *buf, size_t size) {
// ...
}
int main(void) {
func(arr, N);
// ...
}
And this way:
// ...
int main(void) {
func(&arr, N);
// ...
}
Is there any deference in those listings? It seems that the 2nd version passes an array as void **
, but is it really so?
CodePudding user response:
The first is correct and the second is wrong or at least very questionable.
arr
when used in an expression or passed to a function, gets adjusted to a pointer to the first element. So it turns equivalent to char*
.
In the second example, &arr
is one of the few exceptions to this "array decay" rule. Instead of a pointer to the first element, we get a pointer to the whole array, type char(*)[N]
. This type is not compatible with char*
, so if you would attempt to cast the void* buf
to a char*
inside the function, the second example causes a subtle bug.
The reason why the second example compiles at all is because void*
(and only that type, not void**
) is a special pointer type that can be converted to/from any other pointer to object. Should you change the function to
void func(char *buf, size_t size)
Then func(&arr, N);
gives the expected compiler diagnostic "passing argument 1 of 'func' from incompatible pointer type".
Now as it happens, if you write the function like this
void func(void *buf, size_t size) {
char* ptr = buf;
for(int i=0; i<size; i )
{
printf("%c ", ch[i]);
}
}
It will most likely work for either version, because the address of the first item (char*
) is the same as the address of the array (char(*)[N]
). Also, C's peculiar type system allows us to access a memory location of some type through an array or struct of items of that same type ("the strict aliasing rule").
Best practices:
- Use the first version.
- Avoid the use of
void*
when possible, since they are type unsafe. - Be as explicit with types as you can and don't rely on implicit type conversions.