dynamically allocating array of struct

Wayne A. Throop throopw at agarn.dg.com
Tue Apr 11 08:08:57 AEST 1989


> cs411s03 at 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      <the-known-world>!mcnc!rti!xyzzy!throopw



More information about the Comp.lang.c mailing list