[comp.lang.c] C pointers

jcrowe@shaffer.UUCP (Joe Crowe) (02/10/89)

Consider this a niave question.  I have a structure which contains among
other things a pointer to an array of structures declared as follows:

typedef struct XYZ
{
     .
     .
     .
     struct diag_cmd    (*p_cmd_blk)[];
     .
     .
} t_xyz;

     I am allocating storage for the above structures dynamically and
setting the pointer p_cmd_blk manually.  All of this works.  But when
I try various methods of accessing a structure member one of the array
of structures I am getting compiler errors.  I have tried most combinations
but with no luck.  Any ideas??

   Thanks in advance.

Joseph Crowe

scjones@sdrc.UUCP (Larry Jones) (02/11/89)

In article <1707@shaffer.UUCP>, jcrowe@shaffer.UUCP (Joe Crowe) writes:
> Consider this a niave question.  I have a structure which contains among
> other things a pointer to an array of structures declared as follows:
> 
> typedef struct XYZ
> {
>      .
>      .
>      .
>      struct diag_cmd    (*p_cmd_blk)[];
>      .
>      .
> } t_xyz;
> 
>      I am allocating storage for the above structures dynamically and
> setting the pointer p_cmd_blk manually.  All of this works.  But when
> I try various methods of accessing a structure member one of the array
> of structures I am getting compiler errors.  I have tried most combinations
> but with no luck.  Any ideas??

The rule of thumb is C is declarations look just like references
and vice versa.  (Of course, you do have to correct for the
structure name being in a different place in the declaration than
in the usage.)   Just work it out one level at a time.  The references
would look like:

	xyz_struct				- struct XYZ
	xyz_struct.p_cmd_blk			- ptr to ary of structs
	(*xyz_struct.p_cmd_blk)			- ary of structs
	(*xyz_struct.p_cmd_blk)[i]		- struct diag_cmd
	(*xyz_struct.p_cmd_blk)[i].member	- member

----
Larry Jones                         UUCP: uunet!sdrc!scjones
SDRC                                      scjones@sdrc.UU.NET
2000 Eastman Dr.                    BIX:  ltl
Milford, OH  45150                  AT&T: (513) 576-2070
"When all else fails, read the directions."

scs@adam.pika.mit.edu (Steve Summit) (02/13/89)

In article <1707@shaffer.UUCP> jcrowe@shaffer.UUCP (Joe Crowe) writes:
>I have a structure which contains among
>other things a pointer to an array of structures declared as follows:
>typedef struct XYZ
>{
>     struct diag_cmd    (*p_cmd_blk)[];
>} t_xyz;
>
>     I am allocating storage for the above structures dynamically and
>setting the pointer p_cmd_blk manually.  All of this works.

While your declaration of a pointer to an array of structures is
correct, it has two problems:

     1.	The array size isn't specified, making this pointer even
	less useful than most pointers to arrays.

     2.	It probably isn't what you want.

I suspect that the intent was that an XYZ structure contain an
arbitrary number of diag_cmd structures, with the number
unknown at compile time.  That is, you wanted something like

	struct diag_cmd p_cmd_blk[n];

where n is determined at run time (n is probably another member
of the XYZ structure).  What you want is

	struct diag_cmd *p_cmd_blk;

which can be initialized with

	t_xyz.p_cmd_blk =
		(struct diag_cmd *)malloc(n * sizeof(struct diag_cmd));

and dereferenced with

	t_xyz.p_cmd_blk[i].cmd_blk_field

The key is that a pointer to a structure (or any kind of pointer,
for that matter) need not point to only one instance of the
structure.  In this case, it "points at" an "array" of n
structures, although the pointer's type is "pointer to structure"
rather than "pointer to array of structure."  For the usual
cases, "pointer to struct" is in fact preferable; pointer
arithmetic (and, by extension, array-like subscripting) works as
you probably want it to: selecting among the various single
structures in the "array" of n of them.  (In this paragraph, I
have used the terms "points at" and "array", in quotes, in a
loose way -- struct diag_cmd *p_cmd_blk neither declares an
array, nor, formally, points at one, but once allocated, it acts
like an array for all practical purposes.)

"pointer to array of struct" would, on the other hand, increment
or index over entire arrays of structures at once, which is why
it's a fairly useless concept if the size of the array is
unspecified.  (Many compilers get pointers to arrays wrong, which
is both unsurprising, since they're so confusing, and benign,
since they're so rarely useful.  I suspect that "pointer to
array" with the size of the array unspecified should elicit a
warning or error message.  pcc apparently pretends that the size
is zero, because incrementing the pointer adds 0 to it.  My C
interpreter says "missing array dimension.")  Although true pointers
to arrays could be made to work in this example, they would
require extradereferencing and punctuation, and generally only
confuse the issue.

                                            Steve Summit
                                            scs@adam.pika.mit.edu

P.S. This example helps to illustrate why, if something of type
"array of X" appears in a C expression, it is converted into a
pointer with type "pointer to X" (rather than "pointer to array
of X").  The resultant pointer "acts like" the original array;
i.e. after saying p=a, p[i] references a[i].

throopw@xyzzy.UUCP (Wayne A. Throop) (02/13/89)

> jcrowe@shaffer.UUCP (Joe Crowe)
> I have a structure which contains among
> other things a pointer to an array of structures declared as follows:
> typedef struct XYZ
> { ...
>   struct diag_cmd    (*p_cmd_blk)[];
> ... } t_xyz;
> I try various methods of accessing a structure member one of the array
> of structures I am getting compiler errors.  I have tried most combinations
> but with no luck.  Any ideas??

Um.... maybe I'm being naive myself, but did you try the obvious one,
the one you declared it with?  That is,

     (*t_xyz.p_cmd_blk)[N]

"It works for me."

In particular, I did this:

    $ cc -g -o t46 t46.c
    $ mxdb t46
    Scanning executable file...
    (debug) view
        1   #include <malloc.h>
        2   struct diag_cmd { int i };
        3   struct { struct diag_cmd (*p_cmd_blk)[]; } t_xyz;
        4   main(){
    *   5     t_xyz.p_cmd_blk = (struct diag_cmd (*)[])malloc(4);
        6     (*t_xyz.p_cmd_blk)[0].i = 23;
        7   }
    (debug) breakpoint 7;continue
    Stopped at frame 1: line 7 of \t46\main, PC main+024
     breakpoint "0" taken
    (debug) evaluate (*t_xyz.p_cmd_blk)[0].i
    23
    (debug) describe t_xyz
    struct {
       struct {
          int i;
       } (*p_cmd_blk)[];
    } t_xyz;
    (debug) bye

--
The seeds of crime bear bitter fruit.
                --- Dick Tracy
-- 
Wayne Throop      <the-known-world>!mcnc!rti!xyzzy!throopw

cjc@ulysses.homer.nj.att.com (Chris Calabrese[mav]) (02/14/89)

In article <3374@xyzzy.UUCP>, throopw@xyzzy.UUCP (Wayne A. Throop) writes:
| > jcrowe@shaffer.UUCP (Joe Crowe)
| > I have a structure which contains among
| > other things a pointer to an array of structures declared as follows:
| > typedef struct XYZ
| > { ...
| >   struct diag_cmd    (*p_cmd_blk)[];
| > ... } t_xyz;
| > I try various methods of accessing a structure member one of the array
| > of structures I am getting compiler errors.  I have tried most combinations
| > but with no luck.  Any ideas??
| 
| Um.... maybe I'm being naive myself, but did you try the obvious one,
| the one you declared it with?  That is,
| 
|      (*t_xyz.p_cmd_blk)[N]

Um...isn't (*p_cmd_blk)[] an array of pointers, not a pointer to an array?
try *(p_cmd_blk[]).

K&R (old) Page 110 says that int *b[10] is an array of 10 pointers to int;
therefore, struct diag_cmd *p_cmd_blk[] should be an array of pointers to
struct diag_cmd.  Somehow I doubt that the parens around *p_cmd_blk are
grouping things differently.

Ayway, there's always struct diag_cmd **p_cmnd_blk.
-- 
Name:			Christopher J. Calabrese
Brain loaned to:	AT&T Bell Laboratories, Murray Hill, NJ
att!ulysses!cjc		cjc@ulysses.att.com
Obligatory Quote:	``Now, where DID I put that bagel?''

cjc@ulysses.homer.nj.att.com (Chris Calabrese[mav]) (02/14/89)

In article <11216@ulysses.homer.nj.att.com>, I write
> Um...isn't (*p_cmd_blk)[] an array of pointers, not a pointer to an array?
> try *(p_cmd_blk[]).

These things always confuse me to no end.
Advanced C Tips and Techniques (page 218) says (*foo)[] should be a pointer
to an array.  I still think a pointer to a pointer is the best way.
-- 
Name:			Christopher J. Calabrese
Brain loaned to:	AT&T Bell Laboratories, Murray Hill, NJ
att!ulysses!cjc		cjc@ulysses.att.com
Obligatory Quote:	``Now, where DID I put that bagel?''

sarima@gryphon.COM (Stan Friesen) (02/14/89)

In article <1707@shaffer.UUCP> jcrowe@shaffer.UUCP (Joe Crowe) writes:
>
>typedef struct XYZ
>{
>     .
>     .
>     .
>     struct diag_cmd    (*p_cmd_blk)[];
>     .
>     .
>} t_xyz;
>
>     I am allocating storage for the above structures dynamically and
>setting the pointer p_cmd_blk manually.  All of this works.  But when
>I try various methods of accessing a structure member one of the array
>of structures I am getting compiler errors.  I have tried most combinations
>but with no luck.  Any ideas??
>
	Even though I have seen one article with the correct solution,
(you probably meant 'struct diag_cmd *p_cmd_blk'), I will put in my two
cents worth.  This confusion between pointers to the first element of an
array and pointers to arrays is very common.  I would recommend that Mr
Koenig's "C Traps and Pitfalls" become standard reading for everyone
learning 'C'. It has an excellent chapter on just this issue, and is
probably worth the price just for that chapter alone.

-- 
Sarima Cardolandion			sarima@gryphon.CTS.COM
aka Stanley Friesen			rutgers!marque!gryphon!sarima
					Sherman Oaks, CA

chris@mimsy.UUCP (Chris Torek) (02/14/89)

In article <11217@ulysses.homer.nj.att.com> cjc@ulysses.homer.nj.att.com
(Chris Calabrese[mav]) writes:
>These things always confuse me to no end. ...

Indeed.

>I still think a pointer to a pointer is the best way.

No.  Steve Summit posted the correct answer (including the fact that,
other than in a very few special cases, C arrays MUST have a size).
Read his article.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

rbutterworth@watmath.waterloo.edu (Ray Butterworth) (02/15/89)

In article <11217@ulysses.homer.nj.att.com>, cjc@ulysses.homer.nj.att.com (Chris Calabrese[mav]) writes:
> In article <11216@ulysses.homer.nj.att.com>, I write
> > Um...isn't (*p_cmd_blk)[] an array of pointers, not a pointer to an array?
> > try *(p_cmd_blk[]).
> 
> These things always confuse me to no end.
> Advanced C Tips and Techniques (page 218) says (*foo)[] should be a pointer
> to an array.  I still think a pointer to a pointer is the best way.

They are only confusing if one tries to think about it.
The trick is don't think.

i.e.  read it exactly as it says it is, and in the occasional case
where the type you end up with really is array, and if array is not
meaningful in the context, then and only then change array to pointer
to element of array.

e.g. (*foo)[3] explicitly says foo is a pointer to an array of 3
elements, so, if you use sizeof(*foo), then you should get the size of
the array, since that is exactly what you asked for,
but if you use func(*foo), then since it is not possible to pass
arrays to functions you get a pointer to the first element of *foo.
Similarly if you have "x = *foo;", then *foo is an array, but since
you cannot assign arrays (i.e. have them on the right of an =,
i.e. have them as r-values), the compiler silently turns the
reference to the array to a pointer to its first element.

Another handy style guideline to follow is trying to avoid writing
empty [] declarations.  If the [] is empty, then you are talking
about an array of unknown size and in the event that you really do
want the array there is no way that the compiler will know how big
it is.  If you don't know how big an array is, then perhaps you
shouldn't be talking about arrays but about pointers.

In particular never declare a function parameter as an array.
e.g. use "char **argv;", not "char *argv[];".  Since the compiler
will silently convert the second parameter declaration into the
first for you, you might as well declare it that way in the first
place and avoid confusing yourself and others.