[comp.lang.c] Bad Pointer Declaration in 'scandir'

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