Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!watmath!clyde!caip!topaz!nike!ucbcad!ucbvax!decvax!cwruecmp!hal!ncoast!allbery From: allbery@ncoast.UUCP (Brandon Allbery) Newsgroups: net.lang.c,net.micro.pc,net.unix Subject: My pointer stuff: C caught me again (?) but it has truths in it Message-ID: <1267@ncoast.UUCP> Date: Fri, 27-Jun-86 19:33:00 EDT Article-I.D.: ncoast.1267 Posted: Fri Jun 27 19:33:00 1986 Date-Received: Sun, 29-Jun-86 06:28:11 EDT References: <1242@ncoast.UUCP> <418@dg_rtp.UUCP> Reply-To: allbery@ncoast.UUCP (Brandon Allbery) Followup-To: net.lang.c Organization: North Coast Computer Resources Lines: 178 Xref: watmath net.lang.c:9626 net.micro.pc:8890 net.unix:8434 Expires: Quoted from <418@dg_rtp.UUCP> ["Re: Pointers vs. arrays: another dumb question..."], by throopw@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@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)