Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!shadooby!accuvax.nwu.edu!tank!ncar!ames!ucsd!sdcsvax!ucsdhub!calmasd!wlp From: wlp@calmasd.Prime.COM (Walter L. Peterson, Jr.) Newsgroups: comp.lang.c Subject: Re: dynamically allocating array of struct Summary: a better way Keywords: dynamic array struct Message-ID: <263@calmasd.Prime.COM> Date: 6 Apr 89 05:42:01 GMT References: <3658@uhccux.uhcc.hawaii.edu> Distribution: usa Organization: Prime-Calma, San Diego R&D, Object and Data Management Group Lines: 189 In article <3658@uhccux.uhcc.hawaii.edu>, cs411s03@uhccux.uhcc.hawaii.edu (Cs411s03) writes: > > I am having difficulty writing a program which dynamically allocates > an array of structs via malloc() and casting. The program seems to > compile OK, but at run time I am addressing the SAME struct over and > over, I want to step thru them with an index. The program goes like > so: > > /* malloc struct test */ > > #include > #include > > #define NUMRECS 60 > > struct ttst { > int num; > }; > > struct ttst (*tptr)[]; > > main() > { > int i, j; > > if ((tptr = (struct ttst (*)[]) \ > malloc(sizeof(struct ttst) * NUMRECS)) == (struct ttst (*)[]) 0) { > perror("malloc"); > exit(1); > } > > printf("sizeof = %d\n", sizeof(struct ttst) * NUMRECS); > > for (i = j = 0; i < NUMRECS; i++) { > tptr[i]->num = ++j; > printf("Rec: %x %d %d\n", tptr[i], i, tptr[i]->num); > } > > printf("---------------\n"); > > for (i = 0; i < NUMRECS; i++) > printf("Rec: %x %d %d\n", tptr[i], i, tptr[i]->num); > > free(tptr); > exit(0); > } > > The program will do much more than this once completed, this program > was just to test the basic concept of dynamically allocating the > structures rather than just declaring a fixed length array ... > > The first loop looks as if it is working, but the second loop proves it > is not. It seems that the same structure is being written to over and > over. I must be missing something fundamental here ... > > cs411s03!uhccux Yes, you are missing something, but don't feel bad, this DOES seem the intuitive way to do it. I don't know what system you are on, but I have tried your original code on Pyramid (BSD & SYSV), SUN (SunOS (mostly SYSV)) and TURBO-C (Messy-DOS). None of these have malloc.h, so that had to be changed to start. Sun gave the compile warning, zero-length array element on each line that referenced tptr[i], Pyramid compiled OK and TURBO-C, which is pretty much ANSI, had fatal errors and failed to compile at all. It did not like the tptr[i]->num. On both SUN and Pyramid it behaived as you said; the first loop looked OK, but the second didn't. Which is just what I would expect. The solution to this problem is simple once you know a few things about the way C treats arrays and subscripts. The resulting code is also, IMHO, "cleaner" and very easy to read. First: the declaration of the pointer is simpler; just declare a pointer to the structure: struct ttst *tptr; no blank subscripts or other jazz. Second: I would suggest using calloc rather than malloc for several reasons. Reason one is that calloc's arguments make what you are trying to do clearer. The first arg is the number of objects for which you are allocating space and the second arg is the size of one of those objects. The second reason is that calloc will "zero-out" the memory space that it allocates; malloc dosn't (typically). Calloc returns the value of the memory location at the start of the block of memory allocated, which must be cast to the type of object being pointed to; that is: tptr = (struct ttst *)calloc(NUMRECS, sizeof(struct ttst)); This gives you a pointer, tptr, to a block of initialized memory that is NUMRECS * sizeof(struct ttst) bytes long and ensures that C now knows that the pointer tptr points to things that are sizeof(struct ttst) long. It is at this point that an understanding of the way C handles arrays and their subscripts comes in. In C the UNSUBSCRIPTED name of an array is in fact a POINTER TO THE BEGINING OF THE ARRAY. For example, if I declare foo to be an array of 20 integers, then the unsubscripted name foo points to the start of the array. C then uses the subscripts as offsets from the array's starting address, each offset being as long as the type of the array elements, to find each array element. Since in this case we are dealing with a structure we will also need an additional offset to get to each element of the structure at each array element; that is done using the standard structure dot notation, NOT the structure pointer -> notation. The reason for this is (C super-wizards no flames please if this explaination is not *STRICTLY* "by-the-book"; I'm recalling this off the top of my head.) that, since you are using the subscript notation, tptr[i], C is interpreting tptr as the name (and thus address) of an array, each ELEMENT of which is of type struct ttst and not as a pointer to a struct ttst. This means that the notation: tptr[i]->num is wrong (TURBO-C refused to compile using this notation) and should be: tptr[i].num The following code compiles and runs on SUN, Pyramid and TURBO-C and provides the expected output: /* malloc struct test */ #include #define NUMRECS 60 struct ttst { int num; }; main() { int i; struct ttst *tptr; if ((tptr = (struct ttst *)calloc(NUMRECS, sizeof(struct ttst))) == NULL){ perror("malloc"); exit(1); } printf("sizeof = %d\n", sizeof(struct ttst) * NUMRECS); for (i = 0; i < NUMRECS; i++) { tptr[i].num = i; printf("Rec: %x %d %d\n", tptr[i], i, tptr[i].num); } printf("---------------\n"); for (i = 0; i < NUMRECS; i++) printf("Rec: %x %d %d\n", tptr[i], i, tptr[i].num); free(tptr); exit(0); } The only complaint that any of the compilers give is a "warning: structure passed by value" for the printing of tptr[i], using the %x format. I'm not too certain what you were expecting here; you DONT get the address. What you DO get in this example is the hex value of tptr[i].num. Also, notice the change in the first loop. There is no need for your variable "j". I hope all this helps. --------------------------------------- Walt Peterson wlp@calmasd.Prime.COM -- Walt Peterson. Prime - Calma San Diego R&D (Object and Data Management Group) "The opinions expressed here are my own and do not necessarily reflect those Prime, Calma nor anyone else. ...{ucbvax|decvax}!sdcsvax!calmasd!wlp