Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.2 9/18/84; site brl-tgr.ARPA Path: utzoo!watmath!clyde!burl!ulysses!allegra!mit-eddie!godot!harvard!seismo!brl-tgr!tgr!hadron!jsdy@SEISMO.ARPA From: jsdy@SEISMO.ARPA Newsgroups: net.lang.c Subject: Re: C declarations Message-ID: <8302@brl-tgr.ARPA> Date: Wed, 13-Feb-85 01:10:02 EST Article-I.D.: brl-tgr.8302 Posted: Wed Feb 13 01:10:02 1985 Date-Received: Thu, 14-Feb-85 02:17:38 EST Sender: news@brl-tgr.ARPA Organization: Ballistic Research Lab Lines: 120 Becuse of all the verbiage, I had mailed this only to the original poster of the message. It now seems that confusion is more rampnt than I had believed. I'm therefore going to post this publicly. (*sigh*) > ... The [] notation is equivalent > to the * notation, right? Wrong. A pointer [int *ip;] is a unit of memory whose contents will be the address of that thing to which it points. It initially points to -- well, nothing in particular. If you use a pointer, you must put the address of an existing (or allocated) object into it, first. That's why it's an error to take all the UNIX Section 2 function declarations literally -- they all use pointer notation, but some of them (read, write, stat, e.g.) really need a real object to act on. An array (int ia[N];) is actually N real objects of the type of which you have the array. (Did I say that right?) So, in this case, if N == 4, then I have just reserved space for 4 int's. The real objects that exist, here, are ia[0], ia[1], ia[2], and ia[3]. The symbol "ia" here refers to no single existing object. So, now comes the confusing part. "Ia" doesn't refer to any existing object -- so, for instance, an attempt to say: ia = new_value; gets an error from C. But if we use "ia" as a pure value, it appears to have a value which is the address of the first element of the array (often put, "the address of the array"). We can then do pointer arith- metic with this value! In this way, it a p p e a r s to be (but is not) a pointer. Just to be reciprocal, if we now set ip = ia; and try to access ip[0], we find to our delight that it works the other way around: the pointer can a p p e a r to be the pure address of the array (first element of ...). In fact, the pointer still is a memory unit containing said address. Just to confuse things a little bit more, there is one case in which all distinctions are lost. A little history: in early C compilers, there was no way in which anything larger than an int (or maybe a long) could be passed as arguments to functions. [Pointers at that time were considered to be about the size of one or another int. On a really abstract machine, this may or may not be true. It is not true on one poorly designed family of microprocessor: the 80*86.] However, people wanted to pass arrays. "No problem," says the lone language designer, "we'll just pass the pure value which is the address of the array." PRESTO. Whether you pass an array name or a pointer to a function, the argument will be a pointer. Many people first learn this with main(): main(argc, argv, envp) int argc; char **argv; char **envp; { } is exactly identical to: main(argc, argv, envp) int argc; char *argv[]; char *envp[]; { } Within the functions, they are really pointers, no matter how you declare them; and they behave entirely like them. They are separate words of storage containing the address of the arrays of (char *)'s or strings that are, respectively, the arguments and environment variables. However, it is still true that for any other automatic declarations and for all static and external declarations, the distinction between array and pointer remains as I have said. (As far as I know, no implementation of C allows register arrays -- but register pointers are the greatest thing since sliced bits.) > int ptr[] <=> int *ptr > int *ptr[] <=> int **ptr Hopefully, you now understand that the upper left and upper right items are not equivalent, unless they are function arguments. The UL item declares that somewhere there is a set of objects (int's), while the UR object is a single unit of memory pointing off to one or a sequence of said objects. Note that the pointer can point to the first element of an array ("to the array"), and then be incremented by 1 to point to the next element of the array, no matter how big the object in the array "actually" is. Thus the popular notion that the pointer to an object may also be a pointer to an array of said objects. The LL item, of course, is an array of pointers to strings. The '[]' operator binds more closely than the '*' operator. (The only case I can think of offhand where a binop is tighter than a unop.) The LR item is a pointer to a pointer to an int. Of course, the pointer that it points to may be the first in an array of pointers! Thus: ptr -> _____ -> (int) _____ -> (int) ... And it must never be confused with either int iaa[M][N]; or int *(iap[]); the former of which is an actual 2-D array, and the latter of which is a pointer to a single array of int's! Think about it: in the first, iaa[M] is an array of N int's: so you get: int 0, int 1, ..., int N-1, (0 row) ... int 0, int 1, ..., int N-1, (M-1 row) or M * N int's closely packed together! In the second, you have a unit of memory which is the address of a series of int's in a row. Gee, you might as well have said int *iap; for all the goos that does you. (I am hedging the truth here -- that notation is sometimes useful.) > int ptr[]; declares one pointer I'm sure you see the problem with this, now. In fact, with no subscript and no initialiser, this is a zero-length array! > int ptr[] = { 1, 2, 3 }; declares a three element int array. Yup! Mnmmm ... it's getting late. Any further questions will have to be deferred until the next class. [;-)] [Go ahead & write if you want.] Joe Yao hadron!jsdy@seismo.{ARPA,UUCP}