gcc: pointer to array

A

Alexei A. Frounze

Hi all,

I have a question regarding the gcc behavior (gcc version 3.3.4).

On the following test program it emits a warning:
#include <stdio.h>

int aInt2[6] = {0,1,2,4,9,16};
int aInt3[5] = {0,1,2,4,9};

void print1 (const int* p, size_t cnt)
{
while (cnt--)
printf ("%d\n", *p++);
}

void print2 (const int (*p)[5])
{
size_t cnt;
#if 0
// prohibited:
(*p)[0]=0;
#endif
for (cnt=0; cnt<5; cnt++)
printf ("%d\n", (*p)[cnt]);
}

int main()
{
printf ("test begin\n");

print1 (aInt2, sizeof(aInt2)/sizeof(aInt2[0]));
print2 (&aInt3); // <-- warns here

printf ("test end\n");
return 0;
}

The warning is:
MOD.c: In function `main':
MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer type

Why is that? How is this different from using print1 (aInt2, ...)? All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2(). However
the #if 0'd assignment operator inside print2() is correctly handled by
gcc -- an error is generated:
MOD.c: In function `print2':
MOD.c:: error: assignment of read-only location
What's wrong with gcc?

There's another thing about the pointer to the array is... The compiler
doesn't generate a warning if I change in print2()
for (cnt=0; cnt<5; cnt++)
to
for (cnt=0; cnt<6; cnt++)
and lets me access (*p)[5], though I think at least a warning should be
generated here.
It doesn't warn me if I put
aInt3[6] = 0;
into main(). But in both cases the compiler "knows" the real size of the
array, still no warning...
Is this OK???

Thanks,
Alex
P.S. I compile it as gcc MOD.c -Wall -oMOD.exe
 
M

Maxim S. Shatskih

Surely.

"&alnt3" is the same as "alnt3", since alnt3 is an array.

So, you pass int* to print2, and it expects an array of int* - i.e. int**.
 
A

Alexei A. Frounze

Maxim S. Shatskih said:
Surely.

"&alnt3" is the same as "alnt3", since alnt3 is an array.

It's not. :) The values are identical, but the types aren't, strictly
speaking. If you pass &aInt2 to print1(), you'll have a problem. You won't,
if you pass aInt2 or &aInt2[0]. This is clear. And it's not the problem.
So, you pass int* to print2, and it expects an array of int* - i.e.
int**.

int (*p)[5] declares p as a pointer to array of 5 elements of type int. It's
not an array of 5 pointers, nor a pointer to such array!

Alex
--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
(e-mail address removed)
http://www.storagecraft.com

Alexei A. Frounze said:
Hi all,

I have a question regarding the gcc behavior (gcc version 3.3.4).

On the following test program it emits a warning:
#include <stdio.h>

int aInt2[6] = {0,1,2,4,9,16};
int aInt3[5] = {0,1,2,4,9};

void print1 (const int* p, size_t cnt)
{
while (cnt--)
printf ("%d\n", *p++);
}

void print2 (const int (*p)[5])
{
size_t cnt;
#if 0
// prohibited:
(*p)[0]=0;
#endif
for (cnt=0; cnt<5; cnt++)
printf ("%d\n", (*p)[cnt]);
}

int main()
{
printf ("test begin\n");

print1 (aInt2, sizeof(aInt2)/sizeof(aInt2[0]));
print2 (&aInt3); // <-- warns here

printf ("test end\n");
return 0;
}

The warning is:
MOD.c: In function `main':
MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer type

Why is that? How is this different from using print1 (aInt2, ...)? All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2(). However
the #if 0'd assignment operator inside print2() is correctly handled by
gcc -- an error is generated:
MOD.c: In function `print2':
MOD.c:: error: assignment of read-only location
What's wrong with gcc?

There's another thing about the pointer to the array is... The compiler
doesn't generate a warning if I change in print2()
for (cnt=0; cnt<5; cnt++)
to
for (cnt=0; cnt<6; cnt++)
and lets me access (*p)[5], though I think at least a warning should be
generated here.
It doesn't warn me if I put
aInt3[6] = 0;
into main(). But in both cases the compiler "knows" the real size of the
array, still no warning...
Is this OK???

Thanks,
Alex
P.S. I compile it as gcc MOD.c -Wall -oMOD.exe
 
A

Alexei A. Frounze

daniele_athome said:
Alexei said:
void print2 (const int (*p)[5])

arg1 of print2 seems a pointer to a function... isn't it?

It looks very similar, but it's not :) The [] brackets tell the array, not
function, for which they should've been (), like so:
int (*p)(/*argument(s)*/)

Alex
 
A

Alexei A. Frounze

Joe Wright said:
daniele_athome said:
Alexei said:
void print2 (const int (*p)[5])


arg1 of print2 seems a pointer to a function... isn't it?

No. p is a pointer to array 5 of const int. Alexei gets this wrong too.

Excuse me, but what did I get wrong? Isn't what you're trying to say the
same as in my original post (excerpt): "All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2()."?

Alex
 
A

Alexei A. Frounze

Alexei A. Frounze said:
Joe Wright said:
daniele_athome said:
Alexei A. Frounze wrote:

void print2 (const int (*p)[5])


arg1 of print2 seems a pointer to a function... isn't it?

No. p is a pointer to array 5 of const int. Alexei gets this wrong too.

Excuse me, but what did I get wrong? Isn't what you're trying to say the
same as in my original post (excerpt): "All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2()."?

Alex

To clarify further, "... and ensure that *the array (not the pointer)* it's
not modified in anyway inside print2()."
Alex
 
T

Tommi Johnsson

print2 expects pointer to constant array so
how about declaring aInt3 to constant or modify print2 parameter list...


- jt
 
A

Alexei A. Frounze

Yes, this would work fine if aInt3[] were declared as const array... But the
problem is that the compiler allows pointers to consts to non-const data but
warns on pointers to const array to non-const data. That's why I presented
both things in the test program. Kinda odd, don't you think so? I mean, I
can put there a type cast to get rid of the warning, but this warning in its
very core is stupid. Why "const int*" should be better than or in any other
way differ from "const (*int)[]"? Where's the rationale? I don't see it. Any
idea?

Alex

Tommi Johnsson said:
print2 expects pointer to constant array so
how about declaring aInt3 to constant or modify print2 parameter list...


- jt



Hi all,

I have a question regarding the gcc behavior (gcc version 3.3.4).

On the following test program it emits a warning:
#include <stdio.h>

int aInt2[6] = {0,1,2,4,9,16};
int aInt3[5] = {0,1,2,4,9};

void print1 (const int* p, size_t cnt)
{
while (cnt--)
printf ("%d\n", *p++);
}

void print2 (const int (*p)[5])
{
size_t cnt;
#if 0
// prohibited:
(*p)[0]=0;
#endif
for (cnt=0; cnt<5; cnt++)
printf ("%d\n", (*p)[cnt]);
}

int main()
{
printf ("test begin\n");

print1 (aInt2, sizeof(aInt2)/sizeof(aInt2[0]));
print2 (&aInt3); // <-- warns here

printf ("test end\n");
return 0;
}

The warning is:
MOD.c: In function `main':
MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer type

Why is that? How is this different from using print1 (aInt2, ...)? All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2(). However
the #if 0'd assignment operator inside print2() is correctly handled by
gcc -- an error is generated:
MOD.c: In function `print2':
MOD.c:: error: assignment of read-only location
What's wrong with gcc?

There's another thing about the pointer to the array is... The compiler
doesn't generate a warning if I change in print2()
for (cnt=0; cnt<5; cnt++)
to
for (cnt=0; cnt<6; cnt++)
and lets me access (*p)[5], though I think at least a warning should be
generated here.
It doesn't warn me if I put
aInt3[6] = 0;
into main(). But in both cases the compiler "knows" the real size of the
array, still no warning...
Is this OK???

Thanks,
Alex
P.S. I compile it as gcc MOD.c -Wall -oMOD.exe
 
A

Al Bowers

Alexei said:
I have a question regarding the gcc behavior (gcc version 3.3.4).

On the following test program it emits a warning:
#include <stdio.h>

int aInt2[6] = {0,1,2,4,9,16};
int aInt3[5] = {0,1,2,4,9};
void print2 (const int (*p)[5])
{
size_t cnt;
#if 0
// prohibited:
(*p)[0]=0;
#endif
for (cnt=0; cnt<5; cnt++)
printf ("%d\n", (*p)[cnt]);
}

int main()
{
printf ("test begin\n");

print1 (aInt2, sizeof(aInt2)/sizeof(aInt2[0]));
print2 (&aInt3); // <-- warns here

printf ("test end\n");
return 0;
}

The warning is:
MOD.c: In function `main':
MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer type

Why is that?

Try removing the const keyword.
Example:

#include <stdio.h>

void print2 (int (*p)[5])
{
size_t i;

for(i = 0; i < 5; i++)
printf ("%d\n", (*p));
return;
}

int main(void)
{
int p[5] = {1,2,3,4,5};
print2(&p);
return 0;
}
 
J

Joe Wright

Alexei said:
daniele_athome wrote:

Alexei A. Frounze wrote:


void print2 (const int (*p)[5])


arg1 of print2 seems a pointer to a function... isn't it?

No. p is a pointer to array 5 of const int. Alexei gets this wrong too.

Excuse me, but what did I get wrong? Isn't what you're trying to say the
same as in my original post (excerpt): "All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2()."?

Alex


To clarify further, "... and ensure that *the array (not the pointer)* it's
not modified in anyway inside print2()."
Alex

Sorry Alex, I jumped on you in error. It would seem to be a 'const'
issue. If I remove the const qualifier from the print2 parameter it
works. Or if I add const to the array definition..

const int aInt3[5] = {0, 1, 2, 4, 9};

it works too. Go figure. I don't have a good handle on 'const'.
 
T

Tommi Johnsson

Alexei said:
Yes, this would work fine if aInt3[] were declared as const array... But the
problem is that the compiler allows pointers to consts to non-const data but
warns on pointers to const array to non-const data. That's why I presented
both things in the test program. Kinda odd, don't you think so? I mean, I
can put there a type cast to get rid of the warning, but this warning in its
very core is stupid. Why "const int*" should be better than or in any other
way differ from "const (*int)[]"? Where's the rationale? I don't see it. Any
idea?

i think, it's because types differs from each other...
in print1 you declare `p` as an pointer to const qualified int.
-->> pointed value is const qualified
and
in print2 you declare `p` as an pointer to const qualified array of ints
-->> pointed value is array which elements are const qualified.

i see `const int **p` more like `const int (*p)[5]` than `const int *p`
in this case, because array decays to pointer in most cases.

- jt

print2 expects pointer to constant array so
how about declaring aInt3 to constant or modify print2 parameter list...


- jt



Hi all,

I have a question regarding the gcc behavior (gcc version 3.3.4).

On the following test program it emits a warning:
#include <stdio.h>

int aInt2[6] = {0,1,2,4,9,16};
int aInt3[5] = {0,1,2,4,9};

void print1 (const int* p, size_t cnt)
{
while (cnt--)
printf ("%d\n", *p++);
}

void print2 (const int (*p)[5])
{
size_t cnt;
#if 0
// prohibited:
(*p)[0]=0;
#endif
for (cnt=0; cnt<5; cnt++)
printf ("%d\n", (*p)[cnt]);
}

int main()
{
printf ("test begin\n");

print1 (aInt2, sizeof(aInt2)/sizeof(aInt2[0]));
print2 (&aInt3); // <-- warns here

printf ("test end\n");
return 0;
}

The warning is:
MOD.c: In function `main':
MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer
type
Why is that? How is this different from using print1 (aInt2, ...)? All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2().
However
the #if 0'd assignment operator inside print2() is correctly handled by
gcc -- an error is generated:
MOD.c: In function `print2':
MOD.c:: error: assignment of read-only location
What's wrong with gcc?

There's another thing about the pointer to the array is... The compiler
doesn't generate a warning if I change in print2()
for (cnt=0; cnt<5; cnt++)
to
for (cnt=0; cnt<6; cnt++)
and lets me access (*p)[5], though I think at least a warning should be
generated here.
It doesn't warn me if I put
aInt3[6] = 0;
into main(). But in both cases the compiler "knows" the real size of the
array, still no warning...
Is this OK???

Thanks,
Alex
P.S. I compile it as gcc MOD.c -Wall -oMOD.exe
 
A

Alexei A. Frounze

Joe Wright said:
Alexei said:
daniele_athome wrote:

Alexei A. Frounze wrote:


void print2 (const int (*p)[5])


arg1 of print2 seems a pointer to a function... isn't it?

No. p is a pointer to array 5 of const int. Alexei gets this wrong too.

Excuse me, but what did I get wrong? Isn't what you're trying to say the
same as in my original post (excerpt): "All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2()."?

Alex


To clarify further, "... and ensure that *the array (not the pointer)* it's
not modified in anyway inside print2()."
Alex

Sorry Alex, I jumped on you in error. It would seem to be a 'const'
issue. If I remove the const qualifier from the print2 parameter it
works. Or if I add const to the array definition..

const int aInt3[5] = {0, 1, 2, 4, 9};

it works too. Go figure. I don't have a good handle on 'const'.

That's what I'm trying to find explanation for. I mean, not the const,
rather the odd warning.
Anyway, const prohibits modification of data. Putting it in different
positions near * results in treatment of different object as
constant/unalterable. For instance:

int *p - modifiable pointer to modifiable int
const int *p - modifiable pointer to constant int
int* const p = initvalue; - constant pointer to modifiable int
const int* const p = initvalue; - constant pointer to constant int

int** pp - modifiable pointer to modifiable pointer to modifiable int
const int** pp - modifiable pointer to modifiable pointer to constant int
int* const* pp - modifiable pointer to constant pointer to modifiable int
int** const pp = initvalue; - constant pointer to modifiable pointer to
modifiable int
etc etc...

Maybe I should look into c99 or better ask gcc guys what's going on.
I can also try the thing with other compilers. By now I know that Borland's
old Turbo C/C++ 16-bit compiler for DOS handles the pointer to const array
w/o the warning. There're other Borland's, Open Watcom and VC++ to try...
Though, VC++ is known to emit even more stupid warnings (like a=b=0; where a
and b are for e.g. short and int, and 0 says nothing to the compiler).

Best regards,
Alex
 
A

Alexei A. Frounze

Tommi Johnsson said:
Alexei said:
Yes, this would work fine if aInt3[] were declared as const array... But the
problem is that the compiler allows pointers to consts to non-const data but
warns on pointers to const array to non-const data. That's why I presented
both things in the test program. Kinda odd, don't you think so? I mean, I
can put there a type cast to get rid of the warning, but this warning in its
very core is stupid. Why "const int*" should be better than or in any other
way differ from "const (*int)[]"? Where's the rationale? I don't see it. Any
idea?

i think, it's because types differs from each other...
in print1 you declare `p` as an pointer to const qualified int.
-->> pointed value is const qualified
and
in print2 you declare `p` as an pointer to const qualified array of ints
-->> pointed value is array which elements are const qualified.

i see `const int **p` more like `const int (*p)[5]` than `const int *p`
in this case, because array decays to pointer in most cases.

- jt

There were no "const int **p" in the code. Besides, "const int **p" declares
a modifiable pointer to a modifiable pointer to a constant int. There's no
double indirection anywhere in the code.

Anyway, can you suggest a declaration of the function's argument that would
simultaneously satisfy:
- being a pointer to an array of a fixed number of elements, say, 5 integers
- this array is to be constant, in other words, its elements can't be
altered by using the pointer

Can it be declared like that provided the compiler does not emit any warning
if as argument I use an array (its address) that isn't constant?

Why can I do it with one value, e.g. pass a pointer to modifiable int or
modifiable array of ints to a function whose argument is of type "const
int*", but I can not do the same with an array of fixed number of ints?

Alex
 
A

Alexei A. Frounze

Al Bowers said:
If castration of const is out, do not pout.
Casting, a pollution, is one solution.


Very smart :)
(const int (*)[5])

This is even smarter. :)

So, I presume nobody knows what's wrong. I haven't found anything on this
particular thing in C99. Maybe it's just gcc's way to do things... I need
more statistics.
Alex
 
B

Barry Schwarz

Surely.

"&alnt3" is the same as "alnt3", since alnt3 is an array.

The original post defined an array as int aInt3[5]. Ignoring your
typo in the name:

&aInt3 has type pointer to array of 5 int.

aInt3 in most contexts, including the question raised in the
original post, will be converted to the address of the first element
with type pointer to element type. In this case, it is pointer to
int.

The two types are not compatible.
So, you pass int* to print2, and it expects an array of int* - i.e. int**.

The original post passed &aInt3 to print2, so it did not pass an int*.
print2 was defined in the original post as
void print2 (const int (*p)[5])

The argument is declared as type pointer to constant array of 5 int,
not as an array of pointer to int. While an array of int* would be
passed to a function as an int**, the two are not synonymous at all.


<<Remove the del for email>>
 
N

Netocrat

Tommi Johnsson said:
Alexei said:
Yes, this would work fine if aInt3[] were declared as const array...
But the
problem is that the compiler allows pointers to consts to non-const
data but
warns on pointers to const array to non-const data. That's why I presented
both things in the test program. Kinda odd, don't you think so? I
mean, I
can put there a type cast to get rid of the warning, but this warning
in its
very core is stupid. Why "const int*" should be better than or in any other
way differ from "const (*int)[]"? Where's the rationale? I don't see
it. Any
idea?

Yes, see below.
i think, it's because types differs from each other... in print1 you
declare `p` as an pointer to const qualified int. -->> pointed value is
const qualified and
in print2 you declare `p` as an pointer to const qualified array of ints
-->> pointed value is array which elements are const qualified.

i see `const int **p` more like `const int (*p)[5]` than `const int *p`
in this case, because array decays to pointer in most cases.

Yes, the double indirection is the cause of the warning.
There were no "const int **p" in the code.

I don't think jt was saying there was. He was saying that you should be
comparing print2 function's parameter with "const int **p" rather than
with print1's "const int *p" as you have been doing. This is the source
of your confusion.
Besides, "const int **p"
declares a modifiable pointer to a modifiable pointer to a constant int.
There's no double indirection anywhere in the code.

A pointer to an array *is* double indirection. So print2's first
parameter is doubly indirected.
Anyway, can you suggest a declaration of the function's argument that
would simultaneously satisfy:
- being a pointer to an array of a fixed number of elements, say, 5
integers - this array is to be constant, in other words, its elements
can't be altered by using the pointer

No. To the best of my understanding it is not possible according to the
standard.
Can it be declared like that

Like what?
provided the compiler does not emit any
warning if as argument I use an array (its address) that isn't constant?

Why can I do it with one value, e.g. pass a pointer to modifiable int or
modifiable array of ints to a function whose argument is of type "const
int*", but I can not do the same with an array of fixed number of ints?

This question was answered recently in another thread. See
message id <[email protected]>
dated Wed, 6 Jul 2005 22:54:41 +0000 (UTC)
on comp.lang.c
subject Implicit addition of const qualifiers

Hint, try adding a function:

void print3 (const int** p, size_t cnt) {
while (cnt--)
printf ("%d\n", *(*p)++);
}

and in your main code:
int *pInt = aInt2;
print3 (&pInt, sizeof(aInt2)/sizeof(aInt2[0]));

You'll get the same warning.

The problem is the double indirection - the standard won't allow the
non-const to be automatically converted to const in such cases.

Wouldn't you know it - you'll have to go with the poet. A cast is
required.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,077
Latest member
SangMoor21

Latest Threads

Top