My pointer stuff: C caught me again (?) but it has truths in it

Brandon Allbery allbery at ncoast.UUCP
Sat Jun 28 09:33:00 AEST 1986


Expires:

Quoted from <418 at dg_rtp.UUCP> ["Re: Pointers vs. arrays:  another dumb question..."], by throopw at dg_rtp.UUCP (Wayne Throop)...
+---------------
| > Okay, I've another dumb question for everyone:
| 
| A-Hah!  Not a dumb question at all!  It is a question that cuts right to
| the center of the confusion about pointers in C.
+---------------

Believe me, I'm aware of it.  Anyone have a PD Modula 2 compiler for a 68000?

+---------------
| There are two specific casts that are asked about, (struct foo (*)[])
| and (struct foo *).  As I understand it, the question is, where should
| each be used, and why.  No specific examples of the use of either cast
| are given, but I conjecture from previous postings that the first cast
| is used like so:
| 
|     int (*a[N])[];
|     a[M] = (int (*)[]) malloc( (unsigned) O*sizeof(int) );
| 
| This is, of course, correct.  The second cast's use is much more
| obscure... the only thing said about it is:
| 
| > But, if it's in initialized data, you can't do it that way:
| > you can't take a ``pointer to an array''.
| > So the cast is: (struct foo *)
| 
| Lacking an example of where this cast must be used, some questions
| immediately spring to mind.  What "it" is in initialized data?  The
| array or one of the the arrays pointed to?  What "it" is it that
| "can't be done that way".  The cast?  The assignment (or maybe an
| initialization)?  The malloc?  Finally, what "way" is being talked about
| here?  The format of the assignment/initialization?  The method of
| allocating storage?  Zen budhism?
+---------------

I may have messed up, but C's damnable pointer/array stuff has me so confused
I don't know for sure.  The basic idea as I understand it is the C array
versus an malloc'ed one.

The code in question is two analogous sections:

-------- section 1 ---------

struct sfld (*__cursf)[] = (struct sfld (*)[]) 0;

if ((__cursf = (struct sfld (*)[]) calloc(n, sizeof (struct sfld)))
	== (struct sfld (*)[]) 0) ...

----------------------------

This was intended to allocate an array and assign it to a variable of type
``pointer to array of (struct sfld).  I suspect the type is wrong but I'm not
sure how to decalre such a beastie; I suspect that it *does* *not* *exist*
*at* *all* in C, now that I've played with it.

The other section looks like this:

-------- section 2 ---------

struct menu {
	int m_rec;
	struct cmd *m_cmd;
};

struct menu cmdtab[] = {
	orders,		ocmdarr,
	customer,	ccmdarr,
	-1,		(struct cmd *) 0,
};

----------------------------

The dichotomy between these otherwise identical sections (as far as the
``pointer to an array'' is concerned) is that an array DECLARED in C causes
the array name to become a CONSTANT.  Whereas the malloc()'ed one is a POINTER
VARIABLE.  This could easily have been done correctly:

int array[3];	-- should declare a pointer followed by 3 integers, with the
		   pointer initialized to the 3 integers
int array[];	-- should decalre a pointer.

The ``pointers'' I am talking about here are the assembly-language constructs;
C should treat ``int array[]'' as a different type from ``int *ptr'', and
while ``int array[3]'' and ``int array[]'' are the same type, the sized
array's pointer should be treated as a constant.  (This may be arguable.)
BTW, the (struct foo (*)[]) was confusion on my part; it's just plain wrong
for what I was doing.

I have become thoroughly sick of C pointers-vs.-arrays.  Anyone with a
replacement?  If this continues I may go back to programming in BASIC (yes,
it's THAT bad!).

+---------------
| Anyhow, the insightful stuff follows:
| 
| > BUT:  the arrangement in memory is identical!
+---------------

Not for that cast it wasn't.  The actual problem comes from C's closeness to
the machine hardware:

	the malloc()'ed one is type (int *), to the C compiler (to me, int [])
	the declared one is type (int []), to the C compiler
		(which defines (int []) as (int *))
	--btw, what REALLY threw me was the idea of a cast to (int []) --
		huh?  I wholeheartedly agree with your flame re: declaration-
		mirrors-use; that cast is ridiculous!  ((int (*)[]) is worse!)

and they are in fact identical in memory, so the C compiler treats them as
identical period.  Boo hiss; just because on my computer a (long) is the same
size as an (int) doesn't mean I can mix them with impunity.  C (and, more
importantly, lint) deals with (long)->(int)->(short), but NOWHERE is there a
utility to catch misuse of * and [].

+---------------
| "Why isn't the correct type of an int array name (int [])?"
| 
| *GOOD* question.  *VERY* good question.  The answer is "just because".
+---------------

AMEN, HALLELUJAH!!!

+---------------
| Or, if you want to be insulting, because DMR slipped a cog.  This is
| *THE* *MOST* *CONFUSING* thing about C, by far.  An array name, when
| evaluated, does *NOT* *NOT* *NOT* yield an array type.  This is the
| single greatest lunacy of the C language.  It might be argued that this
| is the *ONLY* great lunacy in C, although the declaration-mirrors-use
| rule probably ought to be considered a great lunacy as well.  (In case
| you can't tell, these nasty remarks about array name evaluation in C are
| my opinions only, and only about 60% serious.  Others differ with me.
| However, it is objective fact that this one point causes more confusion
| and error than any other construct in C.  By far.)
+---------------

This one feature is the only one that has me posting confusing (and wrong)
ideas about C on the net.  Abolish it.  If I had lint source I would change it
to force arrays to be (int []) and pointers (int *); of course, malloc() would
have to be ``known'' for this to work, so the size allocated could be checked
and the correct type assigned.  (malloc(sizeof int) shouldn't have to be cast
to (int []), since it's valid for ``int *foo''.)  Meaning, not possible.  C
loses again.  (HELP!)

+---------------
| > That
| > would make much more clear the meaning of the pointer, and would avoid many of
| > the pointer-vs.-array confusions.
| 
| Yes, yes, yes!!!  However, the fact that array names evaluate to the
| address of the first element in the array means that the types "pointer
| to foo" and "pointer to array of foo" *must* indicate the same storage
| layout in C, and this glitch is so deeply ingrained in C that to "fix"
| it would simply yield a new language, not a better C language.  Note
| that this glitch, coupled with the definition of subscripting in terms
| of pointer arithmetic, makes the type "pointer to foo" an unresistably
| convenient near-synonym for "pointer to unknown sized array of foo", and
| thus nearly everybody uses the simpler form.
+---------------

I'm in the process of rewriting programs to use [] where [] is meant and *
where * is meant.

Come to think of it -- can malloc() or similar be typed right anyway?  I
suspect this is why Pascal uses the ``new(pointer)'' construct, known to the
compiler; it's type-able at compile time.  But catching the allocation of an
(int []) (vs. an (int)) from malloc() and forcing the former to be assigned to
a variable of type (int []) and the latter to an (int *) is nearly
impossible even when the language considers (int []) and (int *) to be
different.

Chuck it out & start over, please!

--Brandon (confusion (*)[])
-- 
ihnp4!sun!cwruecmp!ncoast!allbery ncoast!allbery at Case.CSNET ncoast!tdi2!brandon
(ncoast!tdi2!root for business) 6615 Center St. #A1-105, Mentor, OH 44060-4101
Phone: +01 216 974 9210      CIS 74106,1032      MCI MAIL BALLBERY (part-time)



More information about the Comp.unix mailing list