There is nothing wrong with your code. The rules for this are found in the C standard here:
6.3.2.3 Pointers
A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be
converted to a pointer to void and back again; the result shall
compare equal to the original pointer.
For any qualifier q, a pointer to a non-q-qualified type may be
converted to a pointer to the q-qualified version of the type; the
values stored in the original and converted pointers shall compare
equal.
Meaning that any pointer to object type (to a variable) may be converted to a void pointer, unless the pointer is qualified (const or volatile). So it is fine to do
void* vp;
char* cp;
vp = cp;
But it is not ok to do
void* vp;
const char* cp;
vp = cp; // not an allowed form of pointer conversion
So far so good. But when we mix in pointer-to-pointers, const
-ness is a very confusing subject.
When we have a const char** arr
, we have a pointer to pointer to constant char (hint: read the expression from right to left). Or in C standard gibberish: a pointer to a qualified pointer to type. arr
itself is not a qualified pointer though! It just points at one.
free()
expects a pointer to void. We can pass any kind of pointer to it unless we pass a qualified pointer. const char**
is not a qualified pointer, so we can pass it just fine.
A qualified pointer to pointer to type would have been char* const*
.
Note how gcc whines when we try this:
char*const* arr = malloc(10 * sizeof(char*const*));
free(arr);
gcc -std=c11 -pedantic-errors -Wall - Wextra
:
error: passing argument 1 of 'free' discards 'const' qualifier from
pointer target type
Apparently, Visual Studio gives an incorrect diagnostic. Or alternatively you compiled the code as C++, which doesn't allow implicit conversions to/from void*
.