dalegass@dalcs.UUCP (03/23/87)
I believe there is a incorrect pointer declaration in the unix 'scandir' function (or manual page, at least). This has caused me some headaches; the following definition claims to be a pointer to an array of pointers to the strcuture 'direct': struct direct *(*namelist[]); According to my understanding, this should be interpreted as an array of pointers to pointers to the direct structure, which would give dangerous results under certain circumstances. I believe what they want is: struct direct *(*namelist)[]; The old declaration may work since the memory is allocated, although with the extra level of 'indirection' defined, there may be subtle problems. Hopefully this is only in the 'man' page, and the scandir function itself is all right. Is this a real problem, or a fault in my knowledge of C pointers? *************************************************************************** Dale Gass, Dalhousie U., Halifax, N.S., Canada UUCP: {seismo|watmath|utai|garfield}!dalcs!dalegass.UUCP or dalegass@dalcs.UUCP ...!dalcs!dalcsug!dalegass.UUCP or dalegass@dalcsug.UUCP CDN: dalegass@cs.dal.cdn CSNET: dalegass%cs.dal.cdn@ubc.csnet ARPA: dalegass%cs.dal.cdn%ubc.csnet@CSNET-RELAY.ARPA
chris@mimsy.UUCP (Chris Torek) (03/23/87)
In article <2479@dalcs.UUCP> dalegass@dalcs.UUCP (Dale Gass) writes: >I believe there is a incorrect pointer declaration in the unix 'scandir' >function (or manual page, at least) ... : > >struct direct *(*namelist[]); Well, it is certainly misleading. >According to my understanding, this should be interpreted as an array >of pointers to pointers to the direct structure.... I believe [it should >read] struct direct *(*namelist)[]; No: for there is no such thing. A declaration for a pointer to an array must specify the size of the array. In fact, what both the code and the manual *should* say is struct direct ***namelist; That is, the function wants the address of a variable declared as `struct direct **names;'. An example would help: int i, nnames; struct direct **names; extern int alphasort(); nnames = scandir("/tmp", &names, (int (*)()) NULL, alphasort); if (nnames < 0) { complain("cannot read /tmp"); return; } for (i = 0; i < nnames; i++) /* do something with names[i]->d_name */ the code for the scandir function itself reads scandir(..., namelist, ...) ... struct direct *(*namelist[]); ... The compiler, following the rules for conversion of parameter declarations, alters this to `struct direct ***namelist', which is of course correct. (No wonder it works! :-) ) Also unfortunate, incidentally, is the lack of a function to free the memory allocated by scandir(). -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) UUCP: seismo!mimsy!chris ARPA/CSNet: chris@mimsy.umd.edu
dalegass@dalcs.UUCP (03/30/87)
Minor point: In article <5916@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes: > >read] struct direct *(*namelist)[]; > > No: for there is no such thing. A declaration for a pointer to an > array must specify the size of the array. In fact, what both the > code and the manual *should* say is > > struct direct ***namelist; I disagree with this. I think a pointer to an array need not specify the array size. The compiler (all the one's I've dealt with) will allow this omission of array size. In many cases, it is required to be able to allow pointers to different size arrays being passed to a function. struct direct ***namelist will work exactly the same as *(namelist)[], but the latter is a bit more intuitive (if you can call *any* C declarations intuitive). A pointer to an array of pointers to ..... is what the beast actually is. A pointer to a pointer to a pointer to .... will work the same, but leaves a little bit to be desired in the understanding of it. dalegass@dalcs.uucp
rlk@bacchus.UUCP (04/02/87)
In article <2491@dalcs.UUCP> dalegass@dalcs.UUCP (Dale Gass) writes: ]Minor point: ] ]In article <5916@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes: ]> >read] struct direct *(*namelist)[]; ]> ]> No: for there is no such thing. A declaration for a pointer to an ]> array must specify the size of the array. In fact, what both the ]> code and the manual *should* say is ]> ]> struct direct ***namelist; ] ]I disagree with this. I think a pointer to an array need not specify the ]array size. The compiler (all the one's I've dealt with) will allow this ]omission of array size. In many cases, it is required to be able to allow ]pointers to different size arrays being passed to a function. Conceivably, this need not be the case. In practice, sometimes it isn't (read: 80[123]?8[68]), although no one ever calls it that. Most compilers for this architecture set that I am familiar with require you to specify what "model" of code you are using, namely in terms of size of code, data, etc. The fact is, sometimes a pointer is 16 bits and sometimes it is 32 bits (20 bits, if you want to be clever). This could very easily depend on the size of an array. Now, a compiler writer might decide to be smart and have the compiler automatically select what "model" to use, dynamically. The compiler might want to optimize by using 16 bit addresses whenever possible; without knowing the size of an array, it might not know how big the pointer should be. Does the ANSI standard have anything to say to this issue? Not that I particularly care to defend this architecture (it's a kludgy way of extending the address space of a basically 16-bit address space, and it's only slightly more elegant than the bank switching things people did with Z80's and 6502's). It's just that conceivably a pointer to an array isn't just a pointer to an array. Robert^Z
chris@mimsy.UUCP (04/02/87)
>In article <5916@mimsy.UUCP> I wrote: >>>struct direct *(*namelist)[]; >>No: for there is no such thing. A declaration for a pointer to an >>array must specify the size of the array. In article <2491@dalcs.UUCP> dalegass@dalcs.UUCP (Dale Gass) writes: >... I think a pointer to an array need not specify the array size. >The compiler (all the one's I've dealt with) will allow this omission >of array size. Indeed, the declaration allows it---but just try to use the resulting variable: char (*x)[]; Now, what is the address of (*x)[0]? Well, that is easy: it is `value of x plus zero time array-size plus 0', which is of course just `value of x'. What about (*(x+1))[0]? Its address is `value of x plus 1 times array-size plus 0'. Uh oh. (The 4.3BSD C compiler never notices that anything is wrong, and merrily produces the same address as for (*x)[0].) >In many cases, it is required to be able to allow pointers to >different size arrays being passed to a function. Not so. Give an example, and I will show that you are not interpreting C's array/pointer conversion rules correctly. >struct direct ***namelist will work exactly the same as *(*namelist)[], but >the latter is a bit more intuitive (if you can call *any* C declarations >intuitive). A pointer to an array of pointers to ..... is what the beast >actually is. Scandir creates a contiguous memory region---which is not quite the same as an array---of pointers and modifies an argument to point to that region. Calling this `a pointer to an array of pointers' is misleading, because there is no real `array': An array has a size that is known at compile time. As long as you do not need the size, you can pretend one is the other. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) UUCP: seismo!mimsy!chris ARPA/CSNet: chris@mimsy.umd.edu
throopw@dg_rtp.UUCP (04/04/87)
> dalegass@dalcs.UUCP (Dale Gass)> >> chris@mimsy.UUCP (Chris Torek) >>> struct direct *(*namelist)[]; >> No: for there is no such thing. A declaration for a pointer to an >> array must specify the size of the array. In fact, what both the >> code and the manual *should* say is >> struct direct ***namelist; > I disagree with this. I think a pointer to an array need not specify the > array size. I'll stay out of the does-the-array-size-need-to-be-specified argument for the most part, though I will note in passing that K&R and H&S allow it to be absent, while draft X3J11 does not. Most compilers allow it to be absent, but some do not. Thus, the wise portability-minded, starndard-complient coder will avoid such constructs, and replace them with the equivalent pointer constructs. Which is where *I* disagree with Chris. Unusual as it is for Chris to make a mistake, he has made a doozy here (though an easy doozy to make, so to type). In particular, the claim that *(*foo)[], which is a pointer to an array of pointers, should be replaced by ***foo, which is a pointer to a pointer (or an array of pointers) to a pointer (or an array of pointers) is WRONG, WRONG, WRONG! Look at the memory layouts implied by these constructs. *(*foo)[] is talking about THREE kinds of objects. (1) A pointer, (2) an array, and (3) the objects that the array of pointers point to. ***foo, on the other hand, is talking about FOUR kinds of objects. (1) A pointer, (2) the pointer (1) points to, (3) the pointer (2) points to, and (4) {finally} the object that (3) points to. A completely and utterly different memory layout. Be careful folks. Pointers aren't arrays, and arrays are not pointers, and even the experts (such as Chris) can *sometimes* get confused as to where a [] declaration part can and should be simply replaced by a * declaration part. -- "I like you. You're warm and compassionate, like my father." --- Stingray (speaking to the "good cop" of a pair of poplicemen trying to get 'ray to "talk") -- Wayne Throop <the-known-world>!mcnc!rti-sel!dg_rtp!throopw
chris@mimsy.UUCP (04/05/87)
This is getting out of hand, but I cannot let my reputation get tarnished here :-). In article <1575@dg_rtp.UUCP> throopw@dg_rtp.UUCP (Wayne Throop) writes: >... Unusual as it is for Chris to make a mistake, he has made a >doozy here (though an easy doozy to make, so to type). >In particular, the claim that *(*foo)[], which is a pointer to an array >of pointers, should be replaced by ***foo, which is a pointer to a >pointer (or an array of pointers) to a pointer (or an array of pointers) >is WRONG, WRONG, WRONG! I did not (or I hope I did not) make such a claim. Rather, my claim was that the type of `namelist' in scandir should have been (struct direct ***): not (struct direct **[]), as it was in the source and manual page; nor (struct direct *(*)[]), as was suggested in the first article with this title. So let us take a look at the top of scandir: scandir(dirname, namelist, select, dcomp) char *dirname; struct direct *(*namelist[]); /* the parentheses in the line above are unnecessary */ int (*select)(), (*dcomp)(); { ... Lo! Namelist is a *parameter*. And what happens with array declarations when they appear in parameter contexts? And (not that it is now necessary), as a coup de grace (where are the accents? there are no accents on my keyboard!), I quote from the comment immediately preceding the code to scandir() itself: Returns the number of entries and a pointer to a list of pointers to struct direct (through namelist). -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) UUCP: seismo!mimsy!chris ARPA/CSNet: chris@mimsy.umd.edu
dalegass@dalcs.UUCP (04/07/87)
******somebody please tell me what a line-eater is***** If this argument is totally irrelevant and it's bothering people, just let me know, and I'll acquiesce... In article <6145@mimsy.UUCP>, chris@mimsy.UUCP writes: > >In particular, the claim that *(*foo)[], which is a pointer to an array > >of pointers, should be replaced by ***foo, which is a pointer to a > >pointer (or an array of pointers) to a pointer (or an array of pointers) > >is WRONG, WRONG, WRONG! > > I did not (or I hope I did not) make such a claim. Rather, my > claim was that the type of `namelist' in scandir should have been > (struct direct ***): not (struct direct **[]), as it was in the > source and manual page; nor (struct direct *(*)[]), as was suggested > in the first article with this title. > But you did make such a claim: >>According to my understanding, this should be interpreted as an array >>of pointers to pointers to the direct structure.... I believe [it should >>read] struct direct *(*namelist)[]; > >No: for there is no such thing. A declaration for a pointer to an >array must specify the size of the array. In fact, what both the >code and the manual *should* say is > > struct direct ***namelist; Anyhow, I can't agree that ***namelist is more appropriate than *(*namelist)[] since the structure actuallly *is* a pointer to an array of pointers to... A pointer to a pointer to a pointer is what the thing is actually treated like, but a pointer to an array of pointers to.... seems to be a much better (and more readable) style.... ;-) *************************************************************************** Dale Gass, Dalhousie U., Halifax, N.S., Canada UUCP: {seismo|watmath|utai|garfield}!dalcs!dalegass.UUCP or dalegass@dalcs.UUCP ...!dalcs!dalcsug!dalegass.UUCP or dalegass@dalcsug.UUCP CDN: dalegass@cs.dal.cdn CSNET: dalegass%cs.dal.cdn@ubc.csnet ARPA: dalegass%cs.dal.cdn%ubc.csnet@CSNET-RELAY.ARPA
throopw@dg_rtp.UUCP (04/07/87)
>,>>> chris@mimsy.UUCP (Chris Torek) >> throopw@dg_rtp.UUCP (Wayne Throop) >>... Unusual as it is for Chris to make a mistake, he has made a >>doozy here (though an easy doozy to make, so to type). >>In particular, the claim that *(*foo)[] [...] should be replaced by ***foo >>[... is incorrect ...] > I did not (or I hope I did not) make such a claim. Rather, my > claim was that the type of `namelist' in scandir should have been > (struct direct ***): not (struct direct **[]), as it was in the > source and manual page; nor (struct direct *(*)[]), as was suggested > in the first article with this title. Ah. So, rather than Chris serving as an object lesson on how even experts can become confused, I myself serve as an object lesson on how newcomers to a conversation should pay closer attention to the preceeding discussion. But wait! Part of what confused me was that Chris didn't make totally clear how he got his result that (struct direct ***) was the correct type for the formal parameter! Here is a chance to further pontificate! > [...] I quote from > the comment immediately preceding the code to scandir() itself: > Returns the number of entries and a pointer to a list of > pointers to struct direct (through namelist). "A pointer to a ...." hmmmmm... let's construct the "correct" definition from the english description. a pointer to... * a list (array) of... (*)[N] (but with array-pointer equiv, this is just:) * pointers to... ** struct direct (struct direct **) That gives two stars so far, where does the third come from? Aha! from the "Returns [...] (through namelist)"! We need to explicitly pass the location of this (struct direct **), so that scandir can put a value in it! Hence, from the english, the correct type for the formal would be (struct direct ***) (or, if one allows the type (*)[] to represent "pointer to a list of" as Chris does not:) (struct direct *(**)[]) In ANY event, neither **[] nor *(*)[] are correct, just as Chris was trying to say all along. I think. -- I think. I think I am. Therefore I AM... I think. --- Moody Blues Cogito, ergo spud. I think, therefore a yam. --- anon -- Wayne Throop <the-known-world>!mcnc!rti-sel!dg_rtp!throopw