spl@mcnc.org (Steve Lamont) (06/05/89)
Gentlefolk:
The recent discussions about aggregate initializations and so forth
got me to thinking (this is always a dangerous thing) about typedefed
aggregates. I know that you can typedef something like
typedef struct {
float x;
float y;
float z;
} vertex;
and then treat vertex almost in the same way as a primitive type (such
as char, int, float, etc). F'rinstance, you can allocate an array of
vertex in the following manner
vertex *v;
v = ( vertex *) malloc( sizeof( vertex ) * some_number );
and do wonderful things with v.
Now to the nub of my question:
Is it possible to do something like
typedef int vertex[3];
vertex *v;
v = ( vertex *) malloc( sizeof( vertex ) * some_number );
My compiler will swollow it, and, if I play all sorts of funny games
with pointer dereferencing, I can even put numbers into the array v and
pull them out again in some semblance of correct order. However, all of
the solutions I come up with are inelegant, at best.
So, to the question before the house. Is this a sensible thing to do?
Is it even valid C (as I say, I can get both Microsoft 5.1 and BSD 4.3 C
compilers to swollow it)? How do I reference individual elements
(v[0], v[1], v[2]) as I am able to in the first instance (v->x, v->y,
v->z)? Do I have to resort to klugey constructs to use this construction
profitably? Or should I just forget the whole thing?
--
spl
Steve Lamont, sciViGuy EMail: spl@ncsc.org
North Carolina Supercomputing Center Phone: (919) 248-1120
Box 12732/RTP, NC 27709
gwyn@smoke.BRL.MIL (Doug Gwyn) (06/06/89)
In article <4636@alvin.mcnc.org> spl@mcnc.org (Steve Lamont) writes: > Is it possible to do something like > typedef int vertex[3]; Sure; <setjmp.h> is supposed to typedef a jmp_buf like this. All the other questions are answered by "Use the type the way it must be used by its very definition and it will work just fine."
bumby@math.rutgers.edu (Richard Bumby) (06/06/89)
In article <4636@alvin.mcnc.org> spl@mcnc.org (Steve Lamont) writes: > Gentlefolk: > > . . . <stuff omitted> . . . > > Now to the nub of my question: > > Is it possible to do something like > > typedef int vertex[3]; > > vertex *v; > > v = ( vertex *) malloc( sizeof( vertex ) * some_number ); > > . . . <more stuff omitted> . . . > > So, to the question before the house. Is this a sensible thing to do? > Is it even valid C (as I say, I can get both Microsoft 5.1 and BSD 4.3 C > compilers to swollow it)? How do I reference individual elements > (v[0], v[1], v[2]) as I am able to in the first instance (v->x, v->y, > v->z)? Do I have to resort to klugey constructs to use this construction > profitably? Or should I just forget the whole thing? You are really just setting up v as an array, as the following program illustrates. #include <stdio.h> #define N 5 void *malloc( int ); typedef int vertex[3]; main() { vertex *v; int i,j; v = ( vertex *) malloc( sizeof( vertex ) * N ); for ( i = 0 ; i < N ; ++i ) for( j = 0 ; j < 3 ; ++j ) v[i][j] = i*i + j; for ( i = 0 ; i < N ; ++i ) printf( "row %3d: %8d %8d %8d\n" , i , v[i][0] , v[i][1] , v[i][2] ); } /* output: row 0: 0 1 2 row 1: 1 2 3 row 2: 4 5 6 row 3: 9 10 11 row 4: 16 17 18 */ It seems like good C to me. -- --R. T. Bumby ** Math ** Rutgers ** New Brunswick ** (in one form or another for all kinds of mail) [bumby@math.rutgers.edu]
chris@mimsy.UUCP (Chris Torek) (06/06/89)
In article <4636@alvin.mcnc.org> spl@mcnc.org (Steve Lamont) writes: > Is it possible to do something like > > typedef int vertex[3]; This creates a type alias called `vertex' which means `array 3 of int'. > vertex *v; Thus, this declares v as `pointer to array 3 of int', and > v = (vertex *) malloc( sizeof( vertex ) * some_number ); this calls malloc with an argument of `sizeof(int [3])*n' and casts the result to `pointer to array 3 of int'. >My compiler will swallow it, and, if I play all sorts of funny games >with pointer dereferencing, I can even put numbers into the array v and >pull them out again in some semblance of correct order. However, all of >the solutions I come up with are inelegant, at best. The return from malloc, as cast and stored in v (if not nil), is suitable for use as an `array n of array 3 of int' (I am using `n' where you have `some_number'). To talk about the third `vertex', write v[2] (the first vertex is v[0], not v[1]). This is an object of type `array 3 of int'; in most contexts, it is transformed into one of type `pointer to int', which then points to the first of the three `int's. >Is this a sensible thing to do? Yes. >... How do I reference individual elements (v[0], v[1], v[2]) as I am >able to in the first instance (v->x, v->y, >v->z)? v[0][0] is the first int in the first array of 3 ints; v[0][1] is the second int in the first array of 3 ints; v[0][2] is the third int in the first array of 3 ints. All three exist if v != NULL and if n was at least 1. These can also be written as (*v)[0], (*v)[1], and (*v)[2] respectively, and the first has yet another form, **v. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
karl@haddock.ima.isc.com (Karl Heuer) (06/06/89)
In article <4636@alvin.mcnc.org> spl@mcnc.org (Steve Lamont) writes: >Is it possible to do something like > typedef int vertex[3]; > vertex *v; > v = ( vertex *) malloc( sizeof( vertex ) * some_number ); Yes, provided your compiler supports the concept of pointer-to-array.$% Your example would be equivalent to the non-typedef code: int (*v)[3]; v = (int (*)[3])malloc(sizeof(int [3]) * some_number); In either case, accessing an element is done via (*v)[i]. I presume this is the syntax that you found "inelegant". That's a matter of taste, I guess, but it's exactly analogous to (*fp)(arg) for function pointers@, and (*sp).mem for struct pointers, the only difference being that this last one is so common that it has the builtin synonym "sp->mem". Actually, the above paragraph applies to single-object allocations. Since you're allocating a vector (of length some_number) of these vertices, you can reference the i'th coordinate of the n'th vertex in the vector by simply writing "v[n][i]". Looks a lot like a two-dimensional array, right? Not surprising, since in fact (int (*)[3]) is the type of the rvalue that results from a two-d array of type (int [M][3]) after the array decays into a pointer. Now, if the three elements (despite having a common type) are conceptually different and noninterchangeable, so you'd always be referencing them with a constant index, then you should probably stick with the struct definition. If it really needs to be an array, and the notation still bothers you (or if you want to ensure it will port to compilers that don't support array pointers), I recommend "typedef struct {int coord[3];}", which allows you to reference the elements with "v->coord[i]" (single-object allocation) or "v[n].coord[i]" (multiple-object allocation).# Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint ________ $ Note that pointer-to-array-of-int is *not* the same thing as pointer-to- -int-element-of-array, which is much more common. The latter is what you get when you write "p = &a[i]", or when you let an array-of-int decay into a pointer. The former is a pointer to the *entire array* itself, is a very rarely used type, and behaves differently with, e.g., the "++" operator. % I believe some older compilers don't support it. And I know there are many that allow you to have a pointer-to-array, but refuse to believe that "&a" is a legal way to generate such an object. (Fixed in ANSI C.) @ Actually, X3J11 has rewritten the rules so that it's now legal to invoke a function via a pointer without explicitly dereferencing: fp(arg) is legal in ANSI C. Personally, I prefer to maintain the distinction between functions and function-pointers. # This, together with "#define x coord[0]" etc., can be quite useful.
spl@mcnc.org (Steve Lamont) (06/06/89)
In article <Jun.5.17.50.31.1989.803@math.rutgers.edu> bumby@math.rutgers.edu (Richard Bumby) writes: <In article <4636@alvin.mcnc.org> spl@mcnc.org (Steve Lamont) writes: < <> Gentlefolk: <> <> . . . <stuff omitted> . . . <> <> Now to the nub of my question: <> <> Is it possible to do something like <> <> typedef int vertex[3]; < < [question with obvious answer omitted] <It seems like good C to me. <-- < Thanks to <--R. T. Bumby ** Math ** Rutgers ** New Brunswick ** and Doug Gwyn (I think, my apologies if I got the name wrong) for enlightenment. My problem was not thinking pointer! -- spl Steve Lamont, sciViGuy EMail: spl@ncsc.org North Carolina Supercomputing Center Phone: (919) 248-1120 Box 12732/RTP, NC 27709
karzes@mfci.UUCP (Tom Karzes) (06/06/89)
In article <4636@alvin.mcnc.org> spl@mcnc.org (Steve Lamont) writes: > ... > Is it possible to do something like > > typedef int vertex[3]; > > vertex *v; > > v = ( vertex *) malloc( sizeof( vertex ) * some_number ); Yes, you can do this. In this case v has type "int (*)[3]", i.e., a pointer to an array of 3 ints (or a pointer into an array of arrays of 3 ints). Your call to malloc should allocate "some_number" objects of the size of vertex, which is the size of three ints (so the total size is 3 * "some_number" ints). To access the 2nd element (index 1) of the 21st vertex (index 20) in v, you could write v[20][1]. Here, v[20] gets you the 21st vertex, and v[20][1] gets you the 2nd element of that vertex. With the structure version you showed in your original message, if the second element of a vertex corresponds to y, you would have written v[20].y instead. If you add or subtract integers to or from v, it will skip past whole instances of vertex. I.e., (*(v + 5))[i] is the same as v[5][i]. However, beware of precedence. The following are all equivalent: v[i][j] (*(v + i))[j] *(v[i] + j) *(*(v + i) + j) But *(v + i)[j] is equivalent to *((v + i)[j]) which is equivalent to *(*((v + i) + j)) or **((v + i) + j) or **(v + (i + j)) or *v[i + j] or v[i + j][0]. If you get confused, it may help to think of how the case where vertex is wrapped in a struct works. I.e., typedef struct { int p[3]; } vertex; vertex *v; v = (vertex *) malloc(sizeof(vertex) * some_number); Then v[20][1] in the previous example becomes v[20].p[1] in this example, and the following are all equivalent: v[i].p[j] (*(v + i)).p[j] (v + i)->p[j] *(v[i].p + j) *((*(v + i)).p + j) *((v + i)->p + j) Note that in the second and fifth cases above your compiler would give you a syntax error if you left off the parentheses around (*(v + i)).
awd@dbase.UUCP (Alastair Dallas) (06/11/89)
In article <17895@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes: > In article <4636@alvin.mcnc.org> spl@mcnc.org (Steve Lamont) writes: > > Is it possible to do something like > > > > typedef int vertex[3]; > > > >Is this a sensible thing to do? > > Yes. > Of course it is. For example, I like: typedef char FNAME[<system-dependent size>]; Then you can have things like: func(FNAME name, int arg) { FNAME temp; strcpy(temp, name); if (temp[1] == ':') /* drive specified */ ; if (!strcmp(temp, name)) ; ...and so on... There are lots of good uses for typedef'd arrays. /alastair/