Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!bloom-beacon!gatech!mcnc!rti!xyzzy!agarn!throopw From: throopw@agarn.dg.com (Wayne A. Throop) Newsgroups: comp.lang.c Subject: Re: dynamically allocating array of struct Message-ID: <5038@xyzzy.UUCP> Date: 10 Apr 89 22:08:57 GMT References: <3658@uhccux.uhcc.hawaii.edu> Sender: usenet@xyzzy.UUCP Lines: 95 > cs411s03@uhccux.uhcc.hawaii.edu (Cs411s03) >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. I'll tackle this problem in a way different that Chris does. Running the normal typechecking tools over it gives notice that: 35 type mismatch in call to function free Argument 1 is: tptr Its type is: pointer to array of struct ttst The expected type is: pointer to char But it is pretty clear that that isn't the problem. So let's examine the program with some debugging tools. First, let's see what sort of thing a tptr is: (debug) describe tptr struct { int num; } (*tptr)[1]; (debug) global-options,lang pascal (debug) describe tptr ^ARRAY [0..0] OF RECORD num: LONG_INTEGER; END OK, so we see that it is pointer to an array of records containing 32-bit integers. Further, the compiler seems to have filled in an array bound of 1, in place of the missing one in the declaration. Now, as the program runs, it produces an induction variable "i", and evaluates the expression (tptr[i]->num). Let's ask the debugger what all this means: (debug) global-options, lang pascal (debug) describe tptr[0] Error: the reference to be subscripted is not an array or string. Right away, we see that we can't do this in pascal, so as Daffy Duck says "Hmmmmmm. Sump'n amiss here." Let's return to C and run through that again. "Ho. Ha. Guard. Turn. Parry. THRUST!" (debug) global-options, lang c (debug) describe tptr[0] struct { int num; } [1]; Kapwong! The light should be beginning to dawn. We have subscripted a pointer, and are thus about to use a pointer-indirect operator, "->", to indirect an array name. Now, the absolutely bizarre thing about this is that on our local machine using our local compiler, this program works as the original poster apparently expected, because the structs are 32 bits long, as are pointers, as are ints, as are array[1] of these structs. Thus, under our local compiler, the subscript doesn't always refer to the zeroth array element. On most pcc-derived compilers, the compiler will default the array size to zero instead of one, and produce the behavior the original poster saw. The reason this program works on our local machine with our local compiler is a tremendous comedy of errors and coincidences, and I am leaving the details as an excercise for the reader, because when you work it out (as I have), you just have to laugh and/or cry. And I think it makes a good catharsis either way when thinking about C traps and pitfalls. Now, the moral of this story is USE YOUR TOOLS! Use them in novel and innovative ways. Lint failed to find the bug (because of pointer-arithmetic/array-subscript equivalence), but that doesn't exhaust the list of tools for poking around in programs. Read the assembly code. The subscript calculation produced for the various stages of the offending expression was highly enlightning (and amusing). Poke around with a debugger. When you do the subscript and end up with an array (when the code clearly expected a pointer instead), alarm bells should ring, and either the accessing expression should be changed to (*tptr)[i].num or the declaration AND accessing expression changed to struct ttst *tptr; ... tptr[i].num So again: USE YOUR TOOLS! -- Shakespeare was against assembly language coding: "Bloody instructions which being learned, return to plague the inventor." --- M. E. Hopkins quoting Macbeth. -- Wayne Throop !mcnc!rti!xyzzy!throopw