Dynamic array of structures and function call f (const struct_type * const data [])
The following code warns of an incompatible type. What is the correct way to solve this code?
thanks
typedef struct a_struct struct_type;
void f(const struct_type *const data[], unsigned n);
void test(unsigned n)
{
struct_type **v;
assert(n);
v = malloc(n * sizeof(struct_type *));
/* fill v with new struct_type (with a malloc per entry) */
f(v, n); <- WARN on v
}
a source to share
The reason the compiler is complaining is because of the first declaration const
in the f
.
Try to use
void f(struct_type *const data[], unsigned n);
/*...*/
f( v, n );
and you won't get the same warning. Alternatively, you can use v
when you callf
void f(const struct_type *const data[], unsigned n);
/*...*/
f( (const struct_type * const *) v, n );
It's a bit intuitive, but in C, you can't pass pointer-to-pointer-to-nonconst
for pointer-to-pointer-to-const
. They made a special exception so you can pass pointer-to-nonconst
for pointer-to-const
.
Here the question FAQ FAQ "Why can not I pass char **
a function expecting const char **
? :
You can use
pointer-to-T
(for any typeT
) where expectedpointer-to-const-T
. However, the rule (explicit exception) that allows small inconsistencies in qualified pointer types is not applied recursively, but only at the top level. (const char **
ispointer-to-pointer-to-const-char
, and the exception therefore does not apply.)The reason why you cannot assign a value to a
char **
pointerconst char **
is somewhat unclear. Given that the qualifierconst
exists at all, the compiler would like to help you keep promises from changing valuesconst
. This is why you can assignchar *
toconst char *
, but not the other way around: it is clearly safe to addconst
-ness to a simple pointer, but it would be dangerous to take it away. However, suppose you have completed the following more complex series of tasks:const char c = 'x'; /* 1 */ char *p1; /* 2 */ const char **p2 = &p1; /* 3 */ *p2 = &c; /* 4 */ *p1 = 'X'; /* 5 */
On line 3, we assign a to
char **
aconst char **
. (The compiler should be complaining.) On line 4, we assignconst char *
aconst char *
; this is clearly legal. On line 5, we modify what a indicateschar *
- it should be legal. However, p1 ends up pointing to c, which isconst
. This happened on line 4 because * p2 was indeed p1. This was set up on line 3, which is the destination of the form, which is prohibited, which is why line 3 is prohibited.The assignment to
char **
aconst char **
(in both line 3 and the original question) is not an immediate danger. But it sets up a situation in which p2 promises - that the value will ultimately not be changed - cannot be saved.(C ++ has more sophisticated rules for assigning
const
-qualified pointers that allow you to do more kinds of assignments without generating warnings, but still guard against inadvertent attempts to change valuesconst
. C ++ still won't allow assigningchar **
toconst char **
, but that will get you away with assignmentchar **
toconst char * const
*.)In C, if you must assign or pass pointers that have a qualifier mismatch other than the first level of indirection, then you must use explicit casts (e.g. (
const char **
)), although, as always, the need for such a cast may indicate more a deep problem that casting doesn't really fix.References: ISO Sec. 6.1.2.6 Clause 6.3.16.1 Clause 6.5.3 H & S Sec. 7.9.1 p. 221-2
a source to share
Edited based on Rampion's answer. The problem is the double const declaration in the f () declaration.
Warning code:
struct_type ** v;
v = (struct_type **)malloc(10 * sizeof(struct_type *));
f(v);
This compiles without warning:
const struct_type *const* v;
v = (const struct_type **)malloc(10 * sizeof(struct_type *));
f(v);
a source to share
f expects an array of pointers (const struct_type * []) to be entered as input. You are passing a pointer to a struct pointer (const struct_type **).
The best thing to do, IMO, is change the f signature to:
void f(const struct_type *const* data);
Why do you need to pass arrays as arguments to functions?
a source to share