Xref: utzoo comp.lang.c:14162 comp.sys.ibm.pc:21353 Path: utzoo!utgpu!watmath!clyde!att!osu-cis!tut.cis.ohio-state.edu!mailrus!uflorida!haven!uvaarpa!mcnc!rti!xyzzy!throopw From: throopw@xyzzy.UUCP (Wayne A. Throop) Newsgroups: comp.lang.c,comp.sys.ibm.pc Subject: Re: char ***pointer; Message-ID: <1854@xyzzy.UUCP> Date: 17 Nov 88 21:44:07 GMT References: <360@mjbtn.MFEE.TN.US> Organization: Data General, RTP NC. Lines: 134 > root@mjbtn.MFEE.TN.US (Mark J. Bailey) > I have declared: > char ***pointer; > Now I know that *ch is generally pointing to the start of a string, ie, > a list (array) of characters. Mark has already departed into nonstandard (for C) terminology, and so I imagine that many (like myself) will be having to guess at what he really means by his questions. For example, does he mean that the expression (*ch) points to the start of a string when the variable ch is declared as in the example just above? I suspect not, because it just isn't true. Now if something were declared as char *ch, then the expression (ch) (note: not (*ch)) would point to a character which could be one of an array of characters. (Further, in C, when somebody talks about a "list", they are usually talking about independantly allocated nodes connected by pointers. Arrays are called arrays, or sometimes vectors. Much, *much* more rarely lists.) So, to start off, I presume when Mark says "D is a mumble", I presume he means "The identifier in D, if declared as in D, is a mumble". That's how the following makes the most sense. > **ch would be equal to say a list of lists > (or an array of strings, ie, **argv, for example). ***ch would support > a list of lists of lists of characters. I suppose this could be associated > with a two dimensional array of strings. Well, no. If declared as char ***ch, ch is not a two dimensional array of strings, other than in the most abstract, conceptual way. The object named by ch is a pointer. The pointer denotes a member of a one-dimensional array of pointers. Members of this array of pointers each denote a member of another (potentially unique) one-dimentional array of pointers. Finally, members of this last array each denote a member of a (potentially unique) one-dimentional array of characters. The important thing to note is that the only object for which space is allocated by the declaration char ***ch is that for the first pointer. The array of pointers-to-pointers and the arrays of pointers-to-char and the arrays of characters are all left up to the user to allocate. Therefore: > My biggest question here is, when I declare a *ch and then call malloc > to allocate a space for it to point to, I have a string. I can ch++ to > move up the string. But when I have **ch, and subsequently, ***ch, do > I have to call malloc to allocate space for more pointers? Yes, one must allocate all pointers and characters except for ch itself. > For example (using pointer above), > pointer = (char ***) malloc((x)*sizeof(char *)); > to allocate space for the *LIST* of pointers I am wanting to use? No. Space is being allocated for items of type (char *), and then that space is treated as if it were for items of type (char **). The malloc should, instead, look like this: pointer = (char ***) malloc((x)*sizeof(char **)); And, of course, one would then have to allocate space for the second level of pointers as well as for the character arrays: for( i=0; i Can I say **pointer = (char *) newspace? Then can > I say **pointer++ to move to then next space? Depends on what is mean by "then next space". In the example above, one can indeed say **pointer = (char *)malloc(mumble); and one can indeed say **pointer++. Of course, if p was a pointer typed (char ***) and (pointer==p) before the expression (**pointer++) is evaluated, then (pointer==(&p[1])) afterwards. In other words, one would be starting to step through the allocated arrays in fortran, or anti-odometer, order instead of C or odometer order. (Conceptually speaking, of course, since these aren't multi-dimentional arrays, but rather collections of uni-dimentional arrays connected by pointers.) > I also know that *ch can be referenced with ch[] and **ch with > ch[][]. I assume ***ch can use ch[][][], but is this legal? Yes, as long as the data structures to which the declaration char ***ch; refers have been allocated as outlined above. (And, of course, assuming that the brackets are filled in with some subscript values, of course.) > [...] as in > **pointer++ above. I guess you could view that as pointer[0][0] going > to pointer[0][1]. No, that's p[0][0] to p[1][0]. (++) has greater prescedence than (*). This IS one of those topics that comes by once every few months, so there is clearly a lot of confusion about how arrays and pointers relate to each other in C. The way I keep it straight is to remember that the declaration sometype *p; is talking about two chunks of storage, one for a pointer, which is allocated by the declaration, and one for an array of objects of sometype, which the user must allocate. On the other hand, the declaration sometype a[SOMESIZE]; is talking about only one chunk of storage, that for an array of objects of sometype, which the compiler and/or runtime system allocates. Then apply the distinction recursively for multiple dimentions or indirections. The confusion enters because when (a) is mentioned in an expression, it usually evaluates to the address of the first element in the chunk of storage it represents. Since (p) evaluates to the address of the first element in the chunk of storage p has been set to point to, this means that (a) and (p) are often used in exactly the same way in practice, the difference being that in the (p) case the user must allocate and free the chunk of memory that is occupied by the array of sometype objects, and in the (a) case, the compiler takes care of such things. Hope this posting is of some help. -- A is for Atom; they are all so small, That we have not really seen any at all. B is for Bomb. They are much bigger. So, mister you better keep off of the trigger. --- Edward Teller -- Wayne Throop !mcnc!rti!xyzzy!throopw