vector initialization
Chris Torek
chris at mimsy.UUCP
Wed Jun 7 17:33:42 AEST 1989
In article <687 at lakesys.UUCP> chad at lakesys.UUCP (Chad Gibbons) writes:
>Question: is it possible to initialize a vector?
[where `vector' means `object of type pointer to pointer to char']
Yes. The only legal data type that cannot be initialised is a union
(and even that can have an initialiser, albeit restricted, in pANS C).
> I tried using the same syntax as an array of pointers, i.e.
> char *foo[] = { "one", "two", "three", NULL };
>but this would not compile.
The definition above for `foo' is legal: `foo' is an object of type
`array ? of pointer to char' (array 4, after the initialisation is
complete) and the initialiser is of type `array 4 of pointer to char'.
The way the aggregate---everything between the left and right braces
---acquires this type is somewhat convoluted%: it picks up the `array'
part from the variable being initialised, gets the `4' from the actual
number of elements, and gets the `pointer to char' part from both the
variable and the values themselves. The type of a double-quoted string
is `array N of char', where N is the length of the string including the
final \0 character; this reverts to an object of type `pointer to char'
in this initialiser context, so the types of the individual array
elements match. After solidifying foo[] as an `array 4', the types
of both sides of the equal sign match and the whole thing is declared
sane (even if you are no longer, after reading this paragraph).
-----
% Some might say `Byzantine' or `Baroque', but I prefer `Rococo' :-)
-----
>Since I am initializing it, it would seem an array of pointers would
>suffice.
You need an object of type `pointer to pointer to char'. An array of
pointer to char would suffice, if you could create one without giving
it a name, because it would decay into a pointer to pointer to char.
But you cannot create one without naming it---the initialisation for
`foo' above is legal only because there is a context allowing the array
(namely the intialiser for `foo'). C does not have `naked arrays',
with the one exception of double-quoted strings---you cannot, in the
midst of some expression, write
({ "foo", "bar" })[i] /* illegal */
to select either "foo" or "bar" depending on i==0 or i==1. (You
*can* write this in GCC, by using an `initialised cast':
((char *[]){ "foo", "bar" })[i] /* GCC-specific */
The cast provides the shape for the aggregate.) Normally, the only
way to construct an aggregate object (structure or array) is as an
initialiser for a named variable, and the variable provide the shape.
The variable (or, in GCC, the cast) must have an aggregate type,
not a simple pointer type. In essence,
char **p = { "a", "b", "c" }; /* illegal */
provides the wrong context---the compiler thinks, `Aha, we need a
pointer to pointer to char, and we have a left brace which means an
aggregate ... oops, something is wrong, help me Spock....' It
cannot go through its type-matching waltz without first being told
`array, array!'%%.
-----
%% or `Ole, ole!'; but this works only in Spanish-speaking C compilers.
-----
Now that I have told you why you cannot do it (but not in 50 words
or less), here is the rest of the story:
>... something along these lines (from a command list vector):
>
>typedef struct _com {
> char **words;
> int (*fcn)();
> short flags;
>} COM;
>
>...and then initializing the structure in another module by:
>
>COM foo[] = {
> { "one", "two", "three", NULL }, do_num, 0,
> { "exit", "quit", NULL }, quit, 0
>};
For each of the two COM objects foo[0] and foo[1], you need a constant
value of type `char **'. So what we *can* do is this:
char *xxx0[] = { "one", "two", "three", NULL };
char *xxx1[] = { "exit", "quit", NULL };
COM foo[] = {
{ xxx0, do_num, 0 },
{ xxx1, quit, 0 },
};
(I have put back the optional braces in the initialiser for foo[],
and added the optional extra comma after foo[1]'s initialiser.) Each
xxx array is an object of type (char *[]), which degenerates into one
of type (char **), and which is a constant expression after this
degeneration (because it is the address of a global variable). If
we hated making up names, and did not mind restricting ourselves to
GCC, we could instead use
COM foo[] = {
{ (char *[]){ "one", "two", "three", NULL }, do_num, 0 },
{ (char *[]){ "exit", "quit", NULL }, quit, 0 },
};
but the former approach is portable, if somewhat ugly.
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain: chris at mimsy.umd.edu Path: uunet!mimsy!chris
More information about the Comp.lang.c
mailing list