Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Microsoft 'C' - Strange behaviour with doubles

2 views
Skip to first unread message

Robert L. Fair

unread,
May 3, 1986, 8:39:51 PM5/3/86
to
Consider an array of 15 pointers to arrays of doubles:

double (*parray[15])[];

The following code to 'malloc' the actual double array barfs on Microsoft 'C',
with a 'different levels of indirection' warning on the '='.
The code passes through LINT, and compiles OK on UN*X 5.2

char *malloc();

parray[0] = (double*)malloc((unsigned)sizeof(double)*75);

Microsoft produces the same error if the coercion is (double**), (double),
or nothing at all !

Any ideas ?

Rob. Fair
{ihnp4|gamma|bambi}!pyuxv!cim2

Bell Communications Research
Piscataway
New Jersey

Subject:
Newsgroups: general

Brandon Allbery

unread,
May 7, 1986, 6:21:12 PM5/7/86
to
Expires:

Quoted from <2...@pyuxv.UUCP> ["Microsoft 'C' - Strange behaviour with doubles"], by ci...@pyuxv.UUCP (Robert L. Fair)...
+---------------


| Consider an array of 15 pointers to arrays of doubles:
|
| double (*parray[15])[];
|
| The following code to 'malloc' the actual double array barfs on Microsoft 'C',
| with a 'different levels of indirection' warning on the '='.
| The code passes through LINT, and compiles OK on UN*X 5.2
|
| char *malloc();
|
| parray[0] = (double*)malloc((unsigned)sizeof(double)*75);
|
| Microsoft produces the same error if the coercion is (double**), (double),
| or nothing at all !
|
| Any ideas ?

+---------------

double (*parray[15])[]; means:

an indefinitely-sized array of (or a pointer to)
an array of 15
(double *)

You want to allocate an array[15] of (double *)? ``double *parray[15];''
...an array of 15 (double)? ``double parray[15][];''

My compiler (pcc) won't even TAKE ``double (*parray[15])[];'' unless it's
initialized or external; apparently sys5 converts it to the declaration
``double *(*parray[15]);'' -- ptr to array[15] of (double *) -- automatically.

--Brandon
--
decvax!cwruecmp!ncoast!allbery ncoast!all...@Case.CSNET ncoast!tdi2!brandon
(ncoast!tdi2!root for business) 6615 Center St. #A1-105, Mentor, OH 44060-4101
Phone: +01 216 974 9210 CIS 74106,1032 MCI MAIL BALLBERY (part-time)
PC UNIX/UNIX PC - which do you like best? See <11...@ncoast.UUCP> in net.unix.

Wayne Throop

unread,
May 10, 1986, 2:43:47 PM5/10/86
to
Ever alert to save the world from mistaken C code examples that could
have been caught by simple use of lint or other commonly available
tools, our eagle eyed hero finds a particularly silly example. Let's
listen in....

> all...@ncoast.UUCP (Brandon Allbery)

> | Consider an array of 15 pointers to arrays of doubles:
> | double (*parray[15])[];
> | The following code to 'malloc' the actual double array barfs on Microsoft 'C',
> | with a 'different levels of indirection' warning on the '='.
> | The code passes through LINT, and compiles OK on UN*X 5.2
> | char *malloc();
> | parray[0] = (double*)malloc((unsigned)sizeof(double)*75);

> double (*parray[15])[]; means:


> an indefinitely-sized array of (or a pointer to)
> an array of 15
> (double *)

Wrong. It means just what the original poster said it meant. It is an
array of 15 pointers to arrays of double. What the original poster is
mistaken about is that lint doesn't complain about the example. In
particular, given this example

void f(){
double (*a[15])[];
char *malloc();
a[0] = (double *)malloc((unsigned)sizeof(double)*75);
}
lint (on our system at least) says
warning: illegal pointer combination
(4)

I grant you, this isn't very informative, but lint *doesn't* like it,
that much is certain. Let's run a more blabbermouth tool over it.

#1052 4 inconsistent types discovered
(=
(:AREF
(:IDENTIFIER a :AUTO ... )
(:OCT_INT 0))
(:CAST
(:POINTER_TO
(:DOUBLE))
(:FUNCALL
(:IDENTIFIER malloc :EXTERN ... )
(*
(:CAST
(:UNSIGNED)
(:SIZEOF
... ))
(:DEC_INT 75)))))
Types are:
(:POINTER_TO
(:ARRAY_OF
(:DOUBLE)
() ()))
and:
(:POINTER_TO
(:DOUBLE))

As you can see, this is an attempt to assign a pointer-to-double to a
pointer-to-array-of-double. In this case, it is easy to tell that this
is what is going on even without blabbermouth typecheckers. The
declaration of a is of the form (*[])[], making the type of a[0] (*)[],
a pointer to an array. The cast of the return value of malloc was
simply *, that is, a simple pointer. If you want your compiler to shut
up, you should make the cast read (double (*)[]). When the cast is
changed in this way, lint no longer complains. Changing the cast to
(double **) naturally still causes complaint.

The problem as I see it is that the C compiler led the original poster
astray with a misleading error message. The problem isn't with a wrong
level of indirection, but with an assignment of a value of type
pointer-to-scalar to an lvalue of type pointer-to-array. The compiler
in question seems to have the common misconception that
pointers == arrays in C... they do not.

Now, with all that said, I suspect that what was really wanted was this:

void f(){
double *a[15];
char *malloc();
a[0] = (double *)malloc((unsigned)sizeof(double)*75);
}

This is type-correct, and is probably what is wanted. We have here an
array of 15 pointers to (implicitly, variable sized arrays of) double.
To reference the second double in the implicit array pointed to by the
third pointer in a, one would say a[2][1]. To say the same thing with
the original definitions would be (*a[2])[1].

> My compiler (pcc) won't even TAKE ``double (*parray[15])[];'' unless it's
> initialized or external; apparently sys5 converts it to the declaration
> ``double *(*parray[15]);'' -- ptr to array[15] of (double *) -- automatically.

Yes, the pcc seems to be another beastie with odd (and in some cases
incorrect) ideas about pointers and arrays. Sigh.
--
Wayne Throop <the-known-world>!mcnc!rti-sel!dg_rtp!throopw

David Herron, NPR Lover

unread,
May 14, 1986, 10:29:15 AM5/14/86
to
[My mailer doesn't know anything about dg_rtp.UUCP, could you please
let uucpmap@cbosgd know of your existance????]

In article <350@dg_rtp.UUCP> you write:
>> all...@ncoast.UUCP (Brandon Allbery)
>
>> | Consider an array of 15 pointers to arrays of doubles:
>> | double (*parray[15])[];
>> | The following code to 'malloc' the actual double array barfs on Microsoft 'C',
>> | with a 'different levels of indirection' warning on the '='.
>> | The code passes through LINT, and compiles OK on UN*X 5.2
>> | char *malloc();
>> | parray[0] = (double*)malloc((unsigned)sizeof(double)*75);
>
>> double (*parray[15])[]; means:
>> an indefinitely-sized array of (or a pointer to)
>> an array of 15
>> (double *)
>
>Wrong. It means just what the original poster said it meant. It is an
>array of 15 pointers to arrays of double. What the original poster is
>mistaken about is that lint doesn't complain about the example. In
>particular, given this example

I respectively submit that you're full of it and that Brandon is correct.

Using []'s in a declaration is SIMILAR to declaring a pointer, 'cept
that the pointer is an internal constant in the compiler, and if you
fill in a value inside the []'s it allocates some space. A stumbling
point is when a [] declaration is an arg to a function, THAT gets
translated to a * declaration...

Some examples:

char a[] = "this is a character string\n";
char b[];

(oh, they're both external decl's) Tell me tho, what USE is a
the declaration of b[]???? Translating the decl to *b isn't
doing what I SAY, and (on Unix anyway) what I SAY is what I MEAN.
Anyway, compiling I get:

Undefined:
_main
_b

_main is undefined because I don't have a main() obviously.
_b is undefined because it knew that somewhere there's a b[]
and made a reference to it.

Modifying it to read:

char a[] = "this is a character string\n";
main()
{
char b[], *c;
char *malloc();

printf("b = 0x%x\n", b);
/* b = */ c = malloc(5);
printf("b = 0x%x, c = 0x%x\n", b, c);
}

produces:

b = 0x7fffe880
b = 0x7fffe880, c = 0x2800

(BTW, this is a Vax running 4.2BSD, and we have the "hated" pcc,
a value like the one for b is a stack location)

Originally I had the b[] decl by itself and the compiler swallowed it.
(I have no idea what the compiler thought I wanted to do with a b[]...)
But it didn't like it when I had the b = uncommented... (which is
what I'd expect). Looking at the assembler output, b[] is a pointer
to the top of the stack but there's no space allocated to it. There's
only space allocated for the *c.

>
> void f(){
> double (*a[15])[];
> char *malloc();
> a[0] = (double *)malloc((unsigned)sizeof(double)*75);
> }
>lint (on our system at least) says
> warning: illegal pointer combination
> (4)

Right. the pcc says "illegal lhs" or something to that effect. Which
is correct... there's no space allocated to your a.

>
>I grant you, this isn't very informative, but lint *doesn't* like it,
>that much is certain. Let's run a more blabbermouth tool over it.
>

... [deleted, for the sake of brevity, some very interesting output]


>
>As you can see, this is an attempt to assign a pointer-to-double to a
>pointer-to-array-of-double. In this case, it is easy to tell that this
>is what is going on even without blabbermouth typecheckers. The
>declaration of a is of the form (*[])[], making the type of a[0] (*)[],
>a pointer to an array. The cast of the return value of malloc was
>simply *, that is, a simple pointer. If you want your compiler to shut
>up, you should make the cast read (double (*)[]). When the cast is
>changed in this way, lint no longer complains. Changing the cast to
>(double **) naturally still causes complaint.

er... where did you get that program? I agree with it somewhat EXCEPT
it's not making a distinction about CONSTANT pointers a la arrays. It's
an interesting program nonetheless...

I agree with you that the compilers need to produce better error messages.


--
David Herron, cbosgd!ukma!david, da...@UKMA.BITNET, da...@uky.csnet

VLD/VMB

unread,
May 15, 1986, 7:18:03 PM5/15/86
to
double (*parray[15])[] is not "pointer to array[15] of (double *)"
but rather "array of 15 pointers to arrays of doubles".
[] has precedence over *.

I don't know whether this misunderstanding contributed to the
original poster's problem or not. I do know that a lot of
people make this []-vs.-* precedence mistake.

Topher Eliot

unread,
May 22, 1986, 12:18:28 PM5/22/86
to
(I have dropped net.unix from the newsgroups list).
There has been some debate on what the declaration
double (*parray[15])[];
means. David Herron seems to be arguing that it declares a zero-length
array of some sort, which some people and/or compilers might interpret as
being a pointer of the same sort. I admit I found his note a little hard
to follow, so maybe I misunderstood him. But I thought I would add my bit
of net volume in the form of an explanation of HOW I would go about parsing
such a statement. My basic rule, which I have trusted for many years, is
to parse it as if it were an expression, starting inside the parentheses,
and obeying operator precedence rules:

double (*parray[15])[];
^^^^
1. It's an array with 15 elements

double (*parray[15])[];
^^^^^^^^^^^
2. It's an array of 15 pointers.

double (*parray[15])[];
^^^^^^^^^^^^^^^
3. It's an array of 15 pointers to arrays (the sizes of these arrays being
pointed at is not specified).

double (*parray[15])[];
^^^^^^^^^^^^^^^^^^^^^^
4. It's an array of 15 pointers to arrays of doubles.

There's another way to parse it, sort of from the outside in:

double (*parray[15])[];
^^^^^^^^^^^^^^^
1. The expression (*parray[15])[] has type double.

double (*parray[15])[];
^^^^^^^^^^^^^
2. The expression (*parray[15]) has type "array of double", with the size
of the array unspecified.

double (*parray[15])[];
^^^^^^^^^^
3. The expression parray[15] has type "pointer to array of double".

double (*parray[15])[];
^^^^^^
4. parray has type "array of pointers to arrays of doubles", parray has 15
elements.

Notice that both these methods are nice and methodical, and they both come
up with the same result.

I get the impression that at least one of the participants of this
discussion parsed the declaration something along the lines of:

double (*parray[15])[];
^^
1. It's a zero-length array of somethings.

double (*parray[15])[];
^ ^^
2. It's a zero-length array of pointers to something.

double (*parray[15])[];
^^^^^^^^^^^^^^
3. It's a zero-length array of pointers to 15-element arrays of
something.

double (*parray[15])[];
^^^^^^^^^^^^^^^^^^^^^^
4. It's a zero-length array of pointers to 15-element arrays of doubles.

It is my contention that parsing a declaration this way is just plain
wrong, but I admit it's an easy mistake to make, one that I myself made
back before I had given this subject as much thought as I have.

The original discussion involved lint and malloc; I have nothing to add to
that aspect of it, so I am not repeating it here.

Cheers,
Topher Eliot Cyb Systems, Austin, TX (512) 835-2266
{gatech,harvard,ihnp4,nbires,seismo,ucb-vax}!ut-sally!cyb-eng!topher

Wayne Throop

unread,
May 22, 1986, 4:43:40 PM5/22/86
to
> da...@ukma.UUCP (David Herron)
>> throopw@dg_rtp.UUCP (Wayne Throop)
>>> all...@ncoast.UUCP (Brandon Allbery)
>>> | ???

> [My mailer doesn't know anything about dg_rtp.UUCP, could you please
> let uucpmap@cbosgd know of your existance????]

[It has been done, long ago. We are (finally!) on the latest maps.
Also, my .signature shows a path to dg_rtp from mcnc, and mcnc is quite
well known (being part of the backbone, I beleive).]

>>> | Consider an array of 15 pointers to arrays of doubles:
>>> | double (*parray[15])[];

>>> double (*parray[15])[]; means:


>>> an indefinitely-sized array of (or a pointer to)
>>> an array of 15
>>> (double *)

>>Wrong. It means just what the original poster said it meant. It is an
>>array of 15 pointers to arrays of double.

> I respectively submit that you're full of it and that Brandon is correct.

I exasperatedly submit that I'm quite empty of it, and that Brandon is
as wrong as wrong can be. Also, after saying I'm wrong, your examples
go on to support my position strongly, so you've succeeded in puzzling
me no end, as well as prolonging this discussion beyond it's natrual
span.

But meanwhile, long ago, in an address space far, far away....

POINTER WARS

The Evil Empire
has attempted to
perpetuate the fallacy
that pointers are the same
thing as arrays. The brave,
outnumbered, noble, correct, long-
suffering rebel alliance has always maintained
that the Force keeps pointers and arrays distinct.
Our hero (moi) has lived a peaceful existance on the
out-of-the-way node dg_rtp for years, until finally an
empire star destroyer (which insists that stars ("*") in
declarations can be replaced by brackets( "[]")) finds dg_rtp
via the news network, and opens fire....

Let's listen in, as the battle begins...

> [Shhhh-Pfoooo... Shhhh-Pfoooo...]

[You can't fool me, Darth Vader!
I know that's you behind the life-mask!]

> Using []'s in a declaration is SIMILAR to declaring a pointer, 'cept
> that the pointer is an internal constant in the compiler, and if you
> fill in a value inside the []'s it allocates some space. A stumbling
> point is when a [] declaration is an arg to a function, THAT gets
> translated to a * declaration...

Yeah, right, [] is just like a pointer, except that it isn't, really.
Give me a break. A [] declaration always declares an array, and arrays
and pointers are *NOT* (I'll repeat for those who have trouble
understanding this concept: *NOT*) the same thing. The fact that array
formal arguments must "actually" be pointers is no more significant than
the fact that character formal arguments must "actually" be integers.

And while declaring *anything* is to some degree similar to declaring
anything else, pointers and arrays are not really very similar.

> Some examples:
>
> char a[] = "this is a character string\n";
> char b[];
>
> (oh, they're both external decl's) Tell me tho, what USE is a
> the declaration of b[]???? Translating the decl to *b isn't
> doing what I SAY, and (on Unix anyway) what I SAY is what I MEAN.

What's the big deal? This says that "a" is an array 28 characters long
(unless I've counted wrong... which is the reason for this shorthand in
the first place), and storage for "a" is allocated in this file, and
initialized to the given string. In addition, you are saying that "b"
is an array of unknown size, and storage for it is *not* allocated in
this file (that's why it can be of unknown size... the storage will be
allocated somewhere else). (What use is "b"? My good sir, what use is a
baby?) Given all this, is it hardly surprising that

> Anyway, compiling I get:
> Undefined: _b

since you implicitly promised to allocate space for "b" somewhere else,
and then didn't do it. So where's the strangeness? How does all this
flapdoodle support your contention that "double (*parray[15])[]" isn't
an array of pointers to arrays of double?

[ Let me be clear about what "shorthand" I'm talking about above. In
C, the declaration
char a[] = "ab";
is shorthand for
char a[3] = {'a', 'b', '\0'};

(though there is some debate as to whether that "'\0'" should be "0"
instead, or exactly what '\0' means (does it mean zero or ascii
null?))

This is *NOT* the same as the declaration
char *a = "ab";
which isn't shorthand for anything, and which behaves quite
differently. The array declaraction allocates storage of size 3,
and initializes those three characters to the values given. The
pointer declaration allocates storage for one pointer (on our
machine, of size 4), and initializes it to point at the first
character of a constant array of size 3. As I say, quite different.
]

> [another example, simplified:
> f(){
> char b[];
> printf( ... b ...);
> } ]


> Looking at the assembler output, b[] is a pointer
> to the top of the stack but there's no space allocated to it.

Actually, the declaration of b is illegal, and our compiler complains
bitterly about it. I assume your compiler treated it as a zero-sized
array. I doubt that it treated it as a pointer, as you suggest.
(Interestingly, lint doesn't complain about it. It certainly ought to.)

>> [verbose typechecker output, deleted]


> er... where did you get that program? I agree with it somewhat EXCEPT
> it's not making a distinction about CONSTANT pointers a la arrays. It's
> an interesting program nonetheless...

Well, the program is a typechecker that was locally written to check the
rules as laid out in Harbison and Steele, sort of the new testament to
K&R's old. Sadly, I'm not currently at liberty to release it.

It is making all the distinctions it should. It was created in essence
by going through H&S (as well as K&R), and translating the type rules
found there into checks performed against the parse tree of the input C
program. Each error message is in fact related back to where H&S
justifies calling the construct an error. I trust it a fair amount more
than I do lint (though, to my utter dismay, it didn't complain about
"f(){char b[];}" either... if anybody can justify why that should be
legal (as I say, our compiler complains bitterly), I'd appreciate a
message explaining why).

> I agree with you that the compilers need to produce better error messages.

Good. I hope you now also agree that compilers should keep the
differences between pointers and arrays straight. Keep away from the
Dark side of the Force, and you can't go wrong.

I stress again, the declaration

int (*a)[];

is *NOT* (i say) *NOT* (i say again) *NOT* the same as the declaration

int **a;

and any entity that thinks they *are* the same thing is,
quite simply, mistaken. Trust me folks... I'm right about this. If you
think these two are the same, you simply haven't thought about it
enough.

--
"Luke... use the Force!"
--
"He's turned his targeting computer off!"
--
Stay tuned for the next exciting episode,

The Umpire Strikes Out

Coming soon to a netnode near you!

Wayne Throop

unread,
May 22, 1986, 6:26:12 PM5/22/86
to
> da...@ukma.UUCP (David Herron)
>> throopw@dg_rtp.UUCP (Wayne Throop)

Oh yeah, about that example the pcc says "illegal lhs" about...
(Don't know how I let this slip by before. Oh well, I can fix it now.)

>> void f(){
>> double (*a[15])[];
>> char *malloc();
>> a[0] = (double *)malloc((unsigned)sizeof(double)*75);
>> }
>>lint (on our system at least) says
>> warning: illegal pointer combination
>> (4)
>
> Right. the pcc says "illegal lhs" or something to that effect. Which
> is correct... there's no space allocated to your a.

Wrongo. The array "a" is an array of 15 pointers to arrays of double
(is anybody getting bored with this?), and thus has 15 pointer-sizes
allocated for it, on the stack in this case. Take this program for
example:

void main(){
double (*a[15])[];
printf( "elements in a = %d\n",
sizeof(a) / sizeof( double (*)[] ) );
}

Now, let's examine this program with a debugger. Positioning to this
module, and asking it to describe "a", we get

ARRAY [ 0..14 ] OF POINTER TO ARRAY [ 0..0 ] OF FLOAT BOUND 64

That is, this is an array of pointers to arrays of doubles, just as I've
been trying to *tell* you. In particular, there are 15 pointers in this
array (that is, the bounds are 0 to 14). But let's see how much space
the compiler has allocated for this array on the local stack frame. We
position to main, and disassemble the first instruction (the allocation
of stack space), and find

WSAVR 17

OK. That's 15 (octal 17) 32-bit words of storage allocated to "a".
Finally, let's run the blasted thing, and see how many elements *IT*
thinks it allocated for "a":

elements in a = 15

If the pcc says that the assignment is illegal, that's fine with me
since it (sort of) is. But it had better be able to accept

a[0] = (double (*)[])malloc((unsigned)sizeof(double)*75);

Now *this* assignment is perfectly legal, since a[0] is a pointer to
an array of double (that is, (double (*)[])).

Fairly conclusive, I'd say. Are y'all convinced?

--
"I've seen things you people wouldn't believe. Attack ships on fire
off the shoulder of Orion. I watched C-Beams glitter in the dark near
the Tanhauser Gate. All those moments will be lost in time, like tears
in rain. Time to die."
Roy Baty, N6MAA10816, Nexus6, Combat Model
--
"I've seen blunders you people wouldn't believe. Pointers confused
with arrays as arguments. I watched C-hackers make stupid mistakes on
net.lang.c. All of these moments will be lost in time, like a posting
on net.philosophy. Time to logout."
Wayne Throop, throopw@dg_rtp, Comedy Model

fri...@psivax.uucp

unread,
May 24, 1986, 1:54:31 PM5/24/86
to
In article <8...@cyb-eng.UUCP> top...@cyb-eng.UUCP (Topher Eliot) writes:
>There has been some debate on what the declaration
> double (*parray[15])[];
>means. David Herron seems to be arguing that it declares a zero-length
>array of some sort, which some people and/or compilers might interpret as
>being a pointer of the same sort.
[Topher Eliot's parse]

>
> double (*parray[15])[];
> ^^^^
>1. It's an array with 15 elements
>
> double (*parray[15])[];
> ^^^^^^^^^^^
>2. It's an array of 15 pointers.
>
> double (*parray[15])[];
> ^^^^^^^^^^^^^^^
>3. It's an array of 15 pointers to arrays (the sizes of these arrays being
>pointed at is not specified).
>
> double (*parray[15])[];
> ^^^^^^^^^^^^^^^^^^^^^^
>4. It's an array of 15 pointers to arrays of doubles.
>
This is indeed correct, and the problem with this declaration
stems from #3. The declaration declares an array of pointers to
entities of *undefined* size(not zero size). Due to the way pointer
arithmetic is defined in "C" this is not kosher(the compiler cannot
determine how much to add to the pointer). At least one compiler I
know of "accepts" this declaration by treating the unspecified arrays
as having size 1, thus making the declaration eqiuvalent to:

double *parray[15]; /* Array of pointers to double */

Since this is likely what the user really wanted anyway this works
out, but it is still wrong!
--

Sarima (Stanley Friesen)

UUCP: {ttidca|ihnp4|sdcrdcf|quad1|nrcvax|bellcore|logico}!psivax!friesen
ARPA: ??

Brandon Allbery

unread,
May 25, 1986, 12:21:25 PM5/25/86
to
Expires:

Quoted from <357@dg_rtp.UUCP> ["Re: allocating arrays"], by throopw@dg_rtp.UUCP (Wayne Throop)...
+---------------


| > da...@ukma.UUCP (David Herron)
| >> throopw@dg_rtp.UUCP (Wayne Throop)
| >>> all...@ncoast.UUCP (Brandon Allbery)
| >>> | ???

| >>> | Consider an array of 15 pointers to arrays of doubles:
| >>> | double (*parray[15])[];
|
| >>> double (*parray[15])[]; means:
| >>> an indefinitely-sized array of (or a pointer to)
| >>> an array of 15
| >>> (double *)
|
| >>Wrong. It means just what the original poster said it meant. It is an
| >>array of 15 pointers to arrays of double.
|
| > I respectively submit that you're full of it and that Brandon is correct.
|
| I exasperatedly submit that I'm quite empty of it, and that Brandon is
| as wrong as wrong can be. Also, after saying I'm wrong, your examples
| go on to support my position strongly, so you've succeeded in puzzling
| me no end, as well as prolonging this discussion beyond it's natrual
| span.

+---------------

I concede. But it wasn't pointer-vs.-array that threw me; f[] and *f are
identical, whereas f[5] and *f are NOT and neither are f[] = {3} and *f.
What threw me was getting my insides and outsides confused. C declarations
are giving me gray hairs! Anyone for Modula-2?

The declaration is correct, the cast should be to (double **), and MSC is as
screwed up as everything else I've ever seen from Microsoft. (So what's
new?) I'm interested in knowing why your sys5 passed it without an illegal
pointer combo message, though.

g...@sun.uucp

unread,
May 26, 1986, 6:24:07 PM5/26/86
to
> I'm interested in knowing why your sys5 passed it without an illegal
> pointer combo message, though.

I don't know what "it" refers to here, but if "it" is an assignment of a
pointer to an array of X to a pointer to a pointer to X, or something like
that, the reason why the PCC in question (and most other PCCs) passed it is
that PCC has a bug in it. The type checking code in "chkpun" is completely
wrong. It treats pointers and arrays as equivalent everywhere. See
net.bugs.v7/net.bugs.2bsd/net.bugs.4bsd and net.bugs.usg for fixes.
--
Guy Harris
{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
g...@sun.arpa

Gregory Smith

unread,
May 27, 1986, 11:45:32 AM5/27/86
to
In article <11...@ncoast.UUCP> all...@ncoast.UUCP (Brandon Allbery) writes:
>I concede. But it wasn't pointer-vs.-array that threw me; f[] and *f are
>identical, whereas f[5] and *f are NOT and neither are f[] = {3} and *f.
^^^^^^^^^
Wrong. They shouldn't be, anyway.

Let's shed a little reality on this:
int nul_ary[];
int *p;
main(){
int i;
i = nul_ary[0];
i = p[0];
}
------------------ output: ( vax, trimmed )----
.data
.comm _nul_ary,0 ; 0 bytes for nul_ary
.comm _p,4 ; 4 bytes for the pointer
.text
....
movl _nul_ary,-4(fp) ; get i = word @ _nul_ary
movl _p,r0 ; get p in r0
movl (r0),-4(fp) ; get i = word pointed to by p
----------------------
nul_ary is treated as an array that happens to have 0 elements, so
*any* subscript is out of range. It can be seen that `i=nul_ary[0]'
will actually do i=(int)p, since the assembler symbols '_nul_ary' and
'_p' are at the same address. Like I said, out of range.

All four compilers I tried behaved the same way (tho I think 3 are pcc-based).

There are some compilers that represent ( in the symbol table ) an array in
the same way as a pointer. The two are distinguished by setting the array
size to 0 to indicate a pointer. After all, pointers don't have array sizes,
and *nobody* uses 0-sized arrays, right? *wrong*. This is the 'clean' way
of declaring an external array of unspecified size:

extern int array[]; /* or array[0] */

So some compilers will 'accidentally' give you a pointer for a
declaration like this, simply because the dimension in the symbol table is
set to zero, and the resulting entry is the same as that for a pointer.
I.e. The generated code will behave as if you had said `extern int *array;'
Obviously, if the external variable is an array, it ain't gonna woik.

If your compiler produces the same code for both variables in the above
sample prog ( with p and nul_ary ), then it is suffering from this bug.
This should not be construed as a language feature, it is an implementation
botch. Some compilers may get the storage declaration right, and then
get the code generation wrong, so check both.

The only compiler that I know for sure has this botch is C/80 for 8080,
which is not full C anyway. From the way this discussion has been going
there must be others. So if you still think f[] and *f are the same, please
check the generated code. Let me/us know about compilers with this bug.

BTW, if you say f[]={3,4}; the size of the array is set to 2 elements by
counting initializers, so there will be no problem.
--
"We demand rigidly defined areas of doubt and uncertainty!" - Vroomfondel
----------------------------------------------------------------------
Greg Smith University of Toronto UUCP: ..utzoo!utcsri!greg

Wayne Throop

unread,
May 27, 1986, 5:01:21 PM5/27/86
to
> fri...@psivax.UUCP (Sarima (Stanley Friesen))
>> top...@cyb-eng.UUCP (Topher Eliot)

>>There has been some debate on what the declaration
>> double (*parray[15])[];
>>means.

> The declaration declares an array of pointers to


> entities of *undefined* size(not zero size).

Right.

> Due to the way pointer
> arithmetic is defined in "C" this is not kosher(the compiler cannot
> determine how much to add to the pointer). At least one compiler I
> know of "accepts" this declaration by treating the unspecified arrays
> as having size 1, thus making the declaration eqiuvalent to:
>
> double *parray[15]; /* Array of pointers to double */

No, no, no, no, no! (But almost yes. :-)

First, the declaration

double (*a[15])[];

is completely kosher, legal, proper, correct, loyal, honorable, brave,
meaningful, trustworthy, and a fine declaration in its own right.
Harbison and Steele (page 69) say

The length of the array, a constant expression, may be omitted as
long as it is not needed to allocate storage.

It does *not* (I say, *NOT*) declare the same thing as

double *a[15];

nor can any correct compiler for C take these two declarations to be
equivalent. On the other hand, the expression (a[n]+m) *is*
meaningless, since the size of the denotation type of the pointer
expression a[n] is unknown, which is the problem Stanley points out
above.


Now, how do arrays of unknown size get along with pointer arithmetic?
For array subscription to work, what must be known is the size of the
*components* of the array, or the "inter-element spacing" (digression:
size of an element is *not* the same thing as the inter-element spacing,
but in C the latter can be deduced from the former by fiat (not renault,
mind you, this only works for Italian cars :-)). The size of the
containing array need not be known, only the lower bound (which is
always zero in C). Thus, the "innermost" array descriptor (following a
pointer declaration, or in a formal argument or external context) may be
of unknown size.

From this we see that as formal arguments or externals, these
declarations are legal:

int a[];
int b[][10];
int c[][10][10];

and these are not

int d[10][];
int e[10][10][];
int f[10][][10];

and in any context, these declarations are legal

int (*g)[];
int (*h)[][10];
int (*i)[][10][10];

(I will note that, despite the H&S quote above, the legitimacy of the
(*)[] declaration with unknown size is not totally clear, but most
compilers and typecheckers side with me on this.)

Now then, the above is mostly the "no, no, no, no, no" part... what
about the "almost yes" part? Well, it turns out that, due to the
peculiar way pointer/array equivalence works in C, it is impossible to
tell if a pointer-to-foo points to a single foo, or to an element of an
array-of-foo, and therefore if what you want is a pointer which
indicates an array-of-foo, it is often expedient to declare
pointer-to-foo only, and have the array part be implicit via
array-pointer equivalence. Note well that this notion does *not* make
the two forms identical. Let's take these definitions:

int *pi, (*pai)[];

For one example of non-equivalence, to reference "the nth int" via a
pointer to int, one uses

*(pi+n)
or, equivalently
pi[n]

while with a pointer to array of foo, one uses

(*pai)[n]

Uttering "pi" in a value context yields the address of an int (or,
implicitly, the address of the first in an unknown size array of int).
Uttering "pai" in a value context yeilds the address of an array of int.
The distinction between "address of array of int" and "address of the
first element of an array of int" is very important to keep clear. The
two are definitely *not* the same thing. (Trust me. But if you don't,
it might help if you consider what happens when such a pointer is
incremented.)

The brevity of the "pi[n]" notation, and the practical equivalence in
use of this to the "(*pai)[]" form, makes pointer-to-foo the normal way
of talking about pointers to arrays in C. This does *not* mean that the
distinction between these concepts is absent from C, however.
--
"I would have *sworn* that *somebody* understood arrays in C!"
--- overheard in the hallway
--
"'Fiat' is Italian for 'hobby'."
--- Eric Hamilton

Sam Kendall

unread,
May 28, 1986, 3:03:27 PM5/28/86
to
In article <367@dg_rtp.UUCP>, throopw@dg_rtp.UUCP writes:
> (I will note that, despite the H&S quote above, the legitimacy of the
> (*)[] declaration with unknown size is not totally clear, but most
> compilers and typecheckers side with me on this.)

So does K&R. If anybody wants to argue with me on this, I'll find the
section number. Basically, the statement on empty brackets is this: in
a sequence of contiguous `[ ]' pairs, only the first `[ ]' can be
empty. But nowhere is it stated that the empty brackets have to be the
first type modifier. So `type (*)[]' is okay.

----
Sam Kendall { ihnp4 | seismo!cmcl2 }!delftcc!sam
Delft Consulting Corp. ARPA: delftcc!s...@NYU.ARPA

Wayne Throop

unread,
May 29, 1986, 6:04:46 PM5/29/86
to
> all...@ncoast.UUCP (Brandon Allbery)

> I concede. But it wasn't pointer-vs.-array that threw me; f[] and *f are
> identical, whereas f[5] and *f are NOT and neither are f[] = {3} and *f.
> What threw me was getting my insides and outsides confused. C declarations
> are giving me gray hairs! Anyone for Modula-2?

I'm for Modula-2 too. But you don't concede enough, apparently, since
you still think that f[] and *f are the same thing, which they are not,
and you go on to say:

> The declaration is correct, the cast should be to (double **), and MSC is as
> screwed up as everything else I've ever seen from Microsoft. (So what's
> new?) I'm interested in knowing why your sys5 passed it without an illegal
> pointer combo message, though.

Which is WRONG, WRONG, WRONG. The cast should be (double (*)[]). Many
folks still seem to think that declaring arrays of unknown size is the
same as declaring a pointer. It is NOT so. Apparently, I have not
convinced you yet. Let's see what various tools say about this example:

1 char *malloc();
2 void f(){
3 int (*a)[], (*b)[], (*c)[];
4 a = (int **) malloc( (unsigned)sizeof(int)*10 );
5 b = (int (*)[]) malloc( (unsigned)sizeof(int)*10 );
6 c = (int *) malloc( (unsigned)sizeof(int)*10 );
7 }

Well, what ought to happen here? The assignment on line 5 is the only
one which has matching types, so everybody ought to complain about the
other two.

Our compiler doesn't raise a peep for any of the three, but this doesn't
surprise me. C compilers most often take a "parts is parts" attitude,
and ignore minor type issues if the intent is "clear".

Our local typechecker says (compressing some whitespace):

4 inconsistent types discovered
Types are: (:POINTER_TO (:ARRAY_OF (:INT) () ()))
and: (:POINTER_TO (:POINTER_TO (:INT)))
6 inconsistent types discovered
Types are: (:POINTER_TO (:ARRAY_OF (:INT) () ()))
and: (:POINTER_TO (:INT))

Lint, on the other hand, only complains about the assignment on line 6,
saying

warning: illegal pointer combination
(6)

So, much to my disgust, lint doesn't catch what I claim is a blatant
error. So who're ya gonna believe, me or a stupid program? :-)
Let's see if we can't induce lint to see a difference between a pointer
and an array with unknown bounds. Let's consider *this* example:

1 #include "stdio.h"
2 void f(){
3 int (*a)[], **b;
4 printf( "%d %d\n",
5 sizeof *a,
6 sizeof *b );
7 }

This time, our compiler says

Error 276 severity 3 beginning on line 5
You cannot take the size of an array with unknown bounds.

Our local typechecker doesn't raise a peep (it doesn't attempt to
evaluate sizeofs).

And lint, glory be, says

(5) warning: sizeof returns value less than or equal to zero

So, lint *does* know the difference between an array of unknown bounds
and a pointer (it correctly complained about applying sizeof to the
array, and allowed the sizeof of the pointer), it just doesn't complain
if you try to assign a pointer-to-a-pointer to a pointer-to-an-array.
That is, lint has a bug, which answers the question as to why lint
doesn't call "illegal pointer combo" on line 4 of the first example.
Further supporting the contention that lint has a bug, it doesn't
complain about this example, which *everyone* should agree is incorrect:

char *malloc();
void f(){
int (*a)[10];
a = (int **) malloc( (unsigned) sizeof(int)*10 );
}

In this case, lint apparently thinks that (int (*)[10]) is the same type
as (int **), clearly wrong.

Let's look at one more example.

#include "stdio.h"
void main(){
int ia[10] = {1}, (*a)[] = (int (*)[])ia;
int i = 2, pi = &i, **b = &pi;
printf( "%x %x %d %x %x %d\n",
a, *a, **a, b, *b, **b );
}

This program, when run, prints

70000a18 70000a18 1 70000a14 70000a12 2

So, a shows the contents of the pointer a, *a is an array name, and
hence shows the address of the first element pointed to by a, and **a is
an integer, the first one in the array *a. On the other hand b shows
the contents of the pointer b, *b is a pointer, and hence shows the
contents of a second pointer, and **b is an integer, the one pointed to
by *b.

This shows that (*a)[] is talking about two chunks of storage, one being
a pointer to the other, and the other being an array of integers (of
unknown size). **b, on the other hand, is talking about *three* chunks
of storage, one being a pointer to the second, the second being a
pointer to the third, the third being an integer (or, implicitly, an
array of integers of unknown size). Note that in both of these cases,
only the *first* of the chunks of storage being talked about is
allocated by the definition of a or b.

Now, have I convinced you all that (*)[] is not the same thing as **,
or must I get out......... THE RACK! HA HA HAAAAAA!!!

--
"I didn't expect the bloody Spainish Inquisition."
--- Monty Python

R.D.Eager

unread,
May 31, 1986, 8:57:58 AM5/31/86
to

This discussion should move to net.lang.
--
Bob Eager

r...@ukc.UUCP
rde@ukc
...!mcvax!ukc!rde

Phone: +44 227 66822 ext 7589

Guy Harris

unread,
May 31, 1986, 6:58:29 PM5/31/86
to
> That is, lint has a bug...

Yup. See a recent posting in net.bugs.<various flavors of UNIX> for a fix
(unless some of you people out there *want* PCC and "lint" to concur in your
mistaken belief that pointers and arrays are equivalent). Also note that
this fix also permits "lint" to check that you aren't trying to convert a
pointer to an array of, say, 10 "int"s to a pointer to an array of 20
"int"s; that is as questionable as converting a pointer to an "int" as
converting a pointer to a "double".

Computer Center

unread,
Jun 2, 1986, 10:23:51 PM6/2/86
to
>
> (unless some of you people out there *want* PCC and "lint" to concur in your
> mistaken belief that pointers and arrays are equivalent). Also note that

Or do we have confusion between name and object?

K&R, p. 186

An array name is a pointer expression.

p. 210

Every time an identifier of array type appears in an
expression, it is converted into a pointer to the first
member of the array.

So an array is not a pointer but a reference to an array
in an expression is a pointer.

Thos Sumner (...ucbvax!ucsfcgl!ucsfcca.UCSF!thos)

Guy Harris

unread,
Jun 4, 1986, 12:08:03 AM6/4/86
to
> Or do we have confusion between name and object?
> ...

> So an array is not a pointer but a reference to an array
> in an expression is a pointer.

That's part of it, but I strongly suspect that people have been confused by
the fact that when you use an array name in an expression it really means a
pointer to the first member of the array; they interpret this limited
interchangability as meaning pointers and arrays are equivalent.

There's been a discussion in net.lang.c of features to be added to C;
sometimes I think pointers should be *subtracted* from C, since people seem
to get very confused about them. There's plenty of code out there which
indicates that the author thinks that, because the second argument to "stat"
is a "struct stat *", that you *have* to pass it a variable of type "struct
stat *" as its second argument; they declare such a variable, set it to
point to a declared "struct stat", and pass the variable to "stat" instead
of just "&<the struct>". Of course, there's always the code which doesn't
declare the "struct stat", and doesn't initialize the pointer, but just
passes a pointer which points nowhere to "stat"; this pops up every so often
on net.lang.c with the question "Why doesn't this work?" attached.

OK, maybe they're useful, and shouldn't be removed. C classes should spend
*lots* more time on them than they are doing, though, given these problems;
better that people learn in class before they start writing code, than be
forced to ask several thousand people on USENET why their code doesn't work.


--
Guy Harris
{ihnp4, decvax, seismo, decwrl, ...}!sun!guy

g...@sun.com (or g...@sun.arpa)

David J. Fiander

unread,
Jun 6, 1986, 2:33:17 PM6/6/86
to
>> So an array is not a pointer but a reference to an array
>> in an expression is a pointer.
>
>That's part of it, but I strongly suspect that people have been confused by
>the fact that when you use an array name in an expression it really means a
>pointer to the first member of the array; they interpret this limited
>interchangability as meaning pointers and arrays are equivalent.

I discovered a very simple way to thing of the name of an array: think of
it a a constant. That's how the compiler treats it at least, and that is
why the expression:

{
int a[10], *ptr;

ptr = &a;
}

is invalid, you can't take the address of a macro (which the name of
the array is to the compiler.

--
UUCP : {allegra,ihnp4,decvax,utzoo,clyde}!watmath!watnot!djfiander
CSNET : djfiander%wat...@waterloo.CSNET
ARPA : djfiander%watnot%waterlo...@csnet-relay.ARPA
BITNET: djfiande@watdcs

Gilbert Cockton

unread,
Jun 10, 1986, 1:41:21 PM6/10/86
to
In article <39...@sun.uucp> g...@sun.UUCP writes:
>
>There's been a discussion in net.lang.c of features to be added to C;
>sometimes I think pointers should be *subtracted* from C, since people seem
>to get very confused about them.
>
>OK, maybe they're useful, and shouldn't be removed. C classes should spend
>*lots* more time on them than they are doing, though, given these problems;
>better that people learn in class before they start writing code, than be
>forced to ask several thousand people on USENET why their code doesn't work.

Despite reading three years of discussion on and off on the pointer-array
equivalance topic, as a casual user of C, I've never been able to come
up with a clear view on when pointers and arrays are equivalent.
I'm sure much of my confusion has actually been caused by reading the
news.

During some debates, large indigestible tracts have appeared. I
haven't got the time to wade through these and synthesise an idiot's
guide to array-pointer equivalences.

Any volunteers for a simple set of statements that get the message
across? There must be many C compiler experts out there.

All I can start with is a straw man, as I'm no expert.

* given an array of dimensions a x b x c .. x n,
the array name is a pointer to array[0][0][0]..[0]

* the only time this is any real use if when passing arrays by reference
as `array' is easier and safer to write than

&(array[0][0][0]..[0])

as you don't need to bear the array dimensions in mind.

Peter S. Shenkin

unread,
Jun 12, 1986, 1:51:05 PM6/12/86
to
In article <aimmi.769> gil...@aimmi.UUCP (Gilbert Cockton) writes:
>Despite reading three years of discussion on and off on the pointer-array
>equivalance topic, as a casual user of C, I've never been able to come
>up with a clear view on when pointers and arrays are equivalent.
>guide to array-pointer equivalences.
> ...

>Any volunteers for a simple set of statements that get the message
>across? There must be many C compiler experts out there.
>
>All I can start with is a straw man, as I'm no expert.
>
>* given an array of dimensions a x b x c .. x n,
> the array name is a pointer to array[0][0][0]..[0]
>
>* the only time this is any real use if when passing arrays by reference
> as `array' is easier and safer to write than
>
> &(array[0][0][0]..[0])
>
> as you don't need to bear the array dimensions in mind.

I'm no expert either, but figured I could submit my own straw man as
more ammunition for the gurus:

When a function is called with an array as its argument, what
is passed is a pointer to the first element of the array.
That's all there is, there ain't no more.

Peter S. Shenkin Columbia Univ. Biology Dept., NY, NY 10027
{philabs,rna}!cubsvax!peters cubsvax!pet...@columbia.ARPA

Stanley Friesen

unread,
Jun 13, 1986, 3:06:07 PM6/13/86
to
In article <7...@aimmi.UUCP> gil...@aimmi.UUCP (Gilbert Cockton) writes:
>
>Despite reading three years of discussion on and off on the pointer-array
>equivalance topic, as a casual user of C, I've never been able to come
>up with a clear view on when pointers and arrays are equivalent.
>I'm sure much of my confusion has actually been caused by reading the
>news.
>
>Any volunteers for a simple set of statements that get the message
>across? There must be many C compiler experts out there.
>

OK, I'll try. First statement

* A two-dimensional array is an array of one-dimensional arrays, and
multi-dimensioanl arrays are produced by repeating this composition
process.

>All I can start with is a straw man, as I'm no expert.
>
>* given an array of dimensions a x b x c .. x n,
> the array name is a pointer to array[0][0][0]..[0]
>

* Close, the array name is a *constant* pointer to the first
b x c x .. x n dimensional *subarray*, i.e. to array[0].

>* the only time this is any real use if when passing arrays by reference
> as `array' is easier and safer to write than
>
> &(array[0][0][0]..[0])
>
> as you don't need to bear the array dimensions in mind.

* I would say its real use is to allow writing algorithms which
may be applied to any one of several similar arrays by using
a pointer instead of an array and initializing the pointer to
the first element of the array. (especially since 'array' is
equivalent to '&(array[0])' rather than the longer form you
suggest)


To summarize, given the declaration:

TYPE array[a][b][c]...[n];

the following two usages are equivalent:
array &array[0]

Guy Harris

unread,
Jun 14, 1986, 3:00:43 AM6/14/86
to
> When a function is called with an array as its argument, what
> is passed is a pointer to the first element of the array.
> That's all there is, there ain't no more.

Try

When an array name is used in an expression, it is treated as
a pointer to the first element of the array.

It doesn't just happen when an array name is used as an argument; that's
just a special case, since it's an expression.

The *only* other form of pointer/array interchangability is that a
declaration of a formal argument as an array of X is treated as a
declaration of that argument as a pointer to X. No other declarations of
arrays are equivalent to declarations of pointers; this is the one that
seems to bite people. If you declare an array of 20 "int"s in the module
that defines that array, and you want to make an external reference from
another module, do NOT call it a pointer to "int". Call it an array of an
unspecified number of "int"s ("int x[]") if that module doesn't know the
size of the array. Better still, call it an *external" array of an
unspecified number of "int"s ("extern int x[]") and your code will build
even on systems which don't have UNIX's "common block" model of external
definitions and references.

Wayne Throop

unread,
Jun 14, 1986, 2:57:37 PM6/14/86
to
> gil...@aimmi.UUCP (Gilbert Cockton)

> * given an array of dimensions a x b x c .. x n,
> the array name is a pointer to array[0][0][0]..[0]

Not quite. It isn't quite right to say that the array name "is" a
pointer... this is what causes all the confusion. The array name, when
*evaluated*, *yields* an address (except when the object of "sizeof").
Note that here I am using the term "address" to mean a non-lvalue
address expression, and "pointer" to mean an lvalue address expression.
Using this terminology, arrays are *never* pointers (except the usually
cited kludge of an array formal argument.)

> * the only time this is any real use if when passing arrays by reference
> as `array' is easier and safer to write than
>
> &(array[0][0][0]..[0])
>
> as you don't need to bear the array dimensions in mind.

Huh? Since the operation e1[e2] is *defined* in C to be (*(e1+e2)), the
fact that an array name evaluates to the address is used *even* *when*
*an* *array* *is* *subscripted*.


I'm not sure just what you are unclear about. It seems to me that most
people are confused on two points:

1) They think that the fact that pointers and arrays can each be
indirected and subscripted means that they are "the same thing".
This is not the case. They both yeild address values when
evaluated (except when object of sizeof), but they are
describing an entirely different runtime storage arrangement.
2) If they are unconfused on point (1), they think that arrays of
unknown size are pointers. This is *not* the case. This
mistake is probably due to the fact that array formal arguments
are equivalent to pointers, but this is a special case exception
and does *not* make them equivalent in the general case.

If you get straight these things:

- how pointers/arrays are *evaluated*
- what *runtime storage* their declaration implies
- what *operations* can be done on addresses, and how subscripting is
defined in terms of address arithmetic

then you have a chance of understanding arrays and pointers in C. Most
people are confused on one or more of these points.

0 new messages