Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!watmath!clyde!caip!seismo!umcp-cs!chris From: chris@umcp-cs.UUCP (Chris Torek) Newsgroups: net.lang.c Subject: Re: My pointer stuff: C caught me again Message-ID: <2201@umcp-cs.UUCP> Date: Sat, 28-Jun-86 23:56:07 EDT Article-I.D.: umcp-cs.2201 Posted: Sat Jun 28 23:56:07 1986 Date-Received: Mon, 30-Jun-86 04:12:03 EDT References: <1242@ncoast.UUCP> <418@dg_rtp.UUCP> <1267@ncoast.UUCP> Reply-To: chris@maryland.UUCP (Chris Torek) Organization: University of Maryland, Dept. of Computer Sci. Lines: 173 Perhaps I just have an odd mind, but all this pointer/array stuff never really bothered me. In article <1267@ncoast.UUCP> allbery@ncoast.UUCP (Brandon Allbery) writes: >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. Why not simply use a `pointer to struct sfld'? If you intend to use this as `__cursf[i].field', that is what you need. >The other section looks like this: > >struct menu { > int m_rec; > struct cmd *m_cmd; >}; > >struct menu cmdtab[] = { > orders, ocmdarr, > customer, ccmdarr, > -1, (struct cmd *) 0, >}; This looks reasonable to me. >The dichotomy What dichotomy? Using my declarations everything is identical; in /* given `int a[N];' */ a; the type of the expression `a' is `pointer to int'. >between these otherwise identical sections (as far as the >``pointer to an array'' is concerned) You should to have a two-dimensional array in mind in the first place before using `pointer to array N'. In /* int b[M][N]; */ b; the type of the expression `b' is `pointer to array N of int'. (Note that if this is dereferenced, it becomes `array N of int', which in a normal expression is then immediately converted to `pointer to int'. `normal' here means `not a target of sizeof'.) >is that an array DECLARED in C causes the array name to become >a CONSTANT. Not quite, but close. When used as an rvalue the constant has type `pointer to' whatever one element of that array might be. >Whereas the malloc()'ed one is a POINTER VARIABLE. No, it is a pointer expression, with type `pointer to' whatever one element of that array might be. Once it has been assigned to a pointer variable, then that is indeed a pointer variable. There are certainly other ways of handling the typing of arrays; C does it by making arrays second class objects, which is occasionally regrettable, but not too hard to deal with. >+--------------- >| Anyhow, the insightful stuff follows: >| >| > BUT: the arrangement in memory is identical! >+--------------- The arrangement in memory of any array of any dimension is flat. `int a[2][5]' is, aside from typing information, identical to `int a[10]'. This has never bothered me. >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 []) Yes. > the declared one is type (int []), to the C compiler Yes. Note that the first dimension of the array is unimportant after allocation, so the type *is* (int []), not (int [5]) or whatnot. (Again, `sizeof' is peculiar; ignore it.) > (which defines (int []) as (int *)) Only in `most places' (this is perhaps what bothers people; `sizeof' is `peculiar', and so are declarations of formals). >+--------------- >| "Why isn't the correct type of an int array name (int [])?" >| >| *GOOD* question. *VERY* good question. The answer is "just because". >| 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.) >+--------------- Again, it has never bothered me. Arrays are second class objects; you cannot quite name one outside a data declaration. Functions are likewise second class: a function name, when evaluated, does not yeild a function type, but rather a function pointer. Lunacy? I guess you should reserve a place in the nut-house for me (though it is arguable that at UMCP, I am already there :-) ). Incidentally, int (*p)[]; is not really a useful declaration. Pretend you are a compiler: tell me how to find p[3][1] (or, if you prefer, (*(p+3))[1]). Try again with int (*p)[5]; and see if that makes a difference. [answers below] The rule for pointer addition is `multiply the integer value by the size (in bytes) of the pointed-to object, then add that to the address given by the pointer.' Given `int (*p)[]', we want to find p[3][1]. This is equivalent to *((*(p+3))+1). Do the innermost expression first: p+3. Following the pointer addition rule, multiply 3 by the size of whatever p points to. p points to `int []'. How big is this? Got me. It is *not* (sizeof (int *)). See what your compiler says about `sizeof (int [])'. For `int (*p)[5]' and the same reference, we take the size of whatever p points to, and p points to `int [5]'. How big is this? Well, it depends on your machine, but let us suppose you have a Vax; we get 5*4 = 20 bytes. We take the address of location (p + 20 bytes), not the contents, as the type of *p is `int []' (the first subscript drops out of any array type), and since this is used in another expression, convert the type to `int *'. We now want to add one to this pointer, so again we follow the pointer addition rule and take the size of the type of the pointed-to object (int), which is four bytes, and multiply by 1 (remember, we are now doing *( + 1)). happens to be (p + 20 bytes), to which we add 4 bytes. The location of p[3][1] is thus (p + 24 bytes), and the type is `int'. If `p' is a register (call it r11), the expression i = p[3][1]; should compile to movl 24(r11),_i and indeed it does. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@mimsy.umd.edu