[comp.lang.c] Pointer/array compatibility

cs211s14@uhccux.uhcc.hawaii.edu (Julian Cowley) (09/29/89)

I have some basic questions regarding arrays and pointers:

int a[2][3][5], ***ippp, **ipp, *ip, i, j;

i = a[0][0][0];		/* ok */
ip = &a[0][0][0];	/* ok */

ip = a[0][0];		/* why? */
ipp = a[0];		/* why? */
ippp = a;		/* why? */

i = ipp[i][j];		/* why^2? */

Why are the latter expressions legal?  For instance, I thought
that a[0][0] is interpreted as pointer to array 5 of int and ip
as a pointer to int, so they would be incompatible.  It becomes
especially confusing with the next expression: a[0] is a pointer
to an array 3 of array 5 of int, not a pointer to pointer to
int.

Also, ipp[i][j], as indicated in K&R, becomes *(*(ipp + i) + j).
How does the compiler know what size to multiply i by?  It would
seem to me that by the rules of pointer arithmetic, i would be
multiplied by the size of a pointer to int and would give
incorrect results.

Basically what I'm asking here is how the compiler decides that
two pointer expressions are of the same type and how it goes
about deciding the size of a pointed-to object.

Thanks for your help.

Julian Cowley
cs211s14@uhccux.uhcc.hawaii.edu
cs211s14@uhccux.bitnet

flaps@dgp.toronto.edu (Alan J Rosenthal) (09/29/89)

cs211s14@uhccux.uhcc.hawaii.edu (Julian Cowley) writes:
>int a[2][3][5], ***ippp, **ipp, *ip, i, j;
>
>i = a[0][0][0];		/* ok */
>ip = &a[0][0][0];	/* ok */
>
>ip = a[0][0];		/* why? */
>ipp = a[0];		/* why? */
>ippp = a;		/* why? */
>
>i = ipp[i][j];		/* why^2? */

>Why are the latter expressions legal?  For instance, I thought
>that a[0][0] is interpreted as pointer to array 5 of int and ip
>as a pointer to int, so they would be incompatible.

Well, the answer is that ipp = a[0] and ippp = a are not legal!  What compiler
are you using?  (rhetorical question)
PCC says (sunos 3.5):
	"test.c", line 9: warning: illegal pointer combination
	"test.c", line 10: warning: illegal pointer combination

However, ip = a[0][0] is fine.  a[0][0] is array 5 of int, not pointer to array
5 of int.

(I assume the reason you thought it odd that i = ipp[i][j] was legal is because
you thought that ipp = a[0] was legal.)

ajr

cs211s14@uhccux.uhcc.hawaii.edu (Julian Cowley) (09/29/89)

In article <1989Sep28.205805.9786@jarvis.csri.toronto.edu> flaps@dgp.toronto.edu (Alan J Rosenthal) writes:
>I wrote this:
>>int a[2][3][5], ***ippp, **ipp, *ip, i, j;
>>
>>ip = a[0][0];		/* why? */
>>ipp = a[0];		/* why? */
>>ippp = a;		/* why? */
>
>Well, the answer is that ipp = a[0] and ippp = a are not legal!  What compiler
>are you using?  (rhetorical question)

The Ultrix 3.1 cc compiler, which I thought was derived from
PCC (i.e., reliable).  Even lint does not complain about the
expressions.

Well, at least that's cleared up.  So much for getting concrete
answers to simple questions by running a test program through a
compiler.

Julian Cowley
cs211s14@uhccux.uhcc.hawaii.edu
cs211s14@uhccux.bitnet

chris@mimsy.UUCP (Chris Torek) (09/30/89)

Concerning the bogus acceptance of

	int **ipp;
	ipp = <expression of type pointer-to-array-5-of-int>;

in article <4967@uhccux.uhcc.hawaii.edu> cs211s14@uhccux.uhcc.hawaii.edu
(Julian Cowley) writes that he was using
>The Ultrix 3.1 cc compiler, which I thought was derived from
>PCC (i.e., reliable).

The Ultrix VAX `cc' compilers (all of them) are derived from buggy
4.2BSD VAX compilers.  One would think that, 4.3BSD-tahoe having been
out for several years, including its considerably less buggy VAX PCC,
DEC might have at least imported some of the more major fixes.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

karzes@mfci.UUCP (Tom Karzes) (10/03/89)

In article <19880@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
-Concerning the bogus acceptance of
-
-	int **ipp;
-	ipp = <expression of type pointer-to-array-5-of-int>;
-
-The Ultrix VAX `cc' compilers (all of them) are derived from buggy
-4.2BSD VAX compilers.  One would think that, 4.3BSD-tahoe having been
-out for several years, including its considerably less buggy VAX PCC,
-DEC might have at least imported some of the more major fixes.

This isn't entirely accurate.  The original C compilers, including the
original pcc, all accepted this.  Basically, it wouldn't complain about
such assignments provided the number of *'s and []'s matched.  This clearly
doesn't make much sense in any cases involving more than one level of this,
but I know that Dennis Ritchie once claimed that it was legal C.  Perhaps
it was regarded as a sloppy shortcut (I'm not trying to justify it, because
I've always hated it).  Perhaps he actually regarded it as a bug which had
lapsed into a feature.

Here's an excerpt from some mail that Bjarne sent me several years ago
when we were discussing this issue:

>PS Dennis claims that this is C:
>main() 
>{ 
>	int a[5][7] ; 
>	int (*p)[5][7]; 
>	p = (int***) a;				/* no & */
>	printf("a %d p %d *p %d\n",a,p,*p);	/* a == p == *p !!! */
>	(*p)[2][4] = 123 ;
>	printf("%d\n",a[2][4]);			/* 123 */
>}
>It works! Amazing!

My original complaint was that C didn't allow the address-of operator to
be applied to arrays.  In the case of array "a" above, I calimed that "&a"
should be equivalent to "(int (*)[5][7]) a", and in my original example
I used this cast in the assignment to "p".  Apparently Dennis claimed that
you could get away with using "(int ***) a", in spite of the fact that
the types are incompatible and could never be used interchangeably.

My impression is that this has been "fixed" from time to time in various
pcc-derived compilers.  I don't know what the latest AT&T and BSD pcc
compilers do.  My personal preference is to "fix" it and give an error
in cases like this.  I can imagine 3 cases when this might arise:

    1.  It was a genuine bug which needed to be fixed.

    2.  The user knew what he/she wanted, but didn't know to express it
        in C, and eventually discovered that using this cast made the
        compiler shut up and accept the assignment.  In this case the
        user simply didn't know C and could very well be misled by the
        fact that the compiler accepts it, even if it happens to do what
        was intended.

    3.  The user knows how to do it the right way, but knows that the
        compiler will accepts this and is just being lazy.  In this case
        he/she should probably have just used the correct cast in the first
        place.