pointer to an int array

N

Neo

Hi Folks,


#include<stdio.h>
int main()
{
int (*p)[10];
int arr[10];
int i;

p = arr; /* <-- compiler warning */
for(i=0; i <= 12; i++){ /* i <=12 delibrately written code */
*((*p) + i) = i;

printf("%d\n", p[0]);
}

return 0;
}

In the above program compiler is giving following warning

$gcc pointer2array.c
pointer2array.c: In function `main':
pointer2array.c:8: warning: assignment from incompatible pointer type

Why the warning?

O'kay and what is the use of int (*p)[10] type of declaration ?
Does the compiler perform any check on the array bounds?
lets say if i declare int arr[12]...
-Neo
 
J

Jack Klein

Hi Folks,


#include<stdio.h>
int main()
{
int (*p)[10];
int arr[10];
int i;

p = arr; /* <-- compiler warning */

The name of an array in an expression, other than when it is the
operand of the 'sizeof' or '&' operators, is converted to a pointer to
its first element. So in the statement above, you are assigning the
address of an int (arr[0]) to a pointer to an array. But arr[0] is an
int, not an array of ints.

Replace with:

p = &arr;
for(i=0; i <= 12; i++){ /* i <=12 delibrately written code */
*((*p) + i) = i;

printf("%d\n", p[0]);
}

return 0;
}

In the above program compiler is giving following warning

$gcc pointer2array.c
pointer2array.c: In function `main':
pointer2array.c:8: warning: assignment from incompatible pointer type

Why the warning?

O'kay and what is the use of int (*p)[10] type of declaration ?
Does the compiler perform any check on the array bounds?
lets say if i declare int arr[12]...
 
N

Neo

Jack Klein said:
Hi Folks,


#include<stdio.h>
int main()
{
int (*p)[10];
int arr[10];
int i;

p = arr; /* <-- compiler warning */

The name of an array in an expression, other than when it is the
operand of the 'sizeof' or '&' operators, is converted to a pointer to
its first element. So in the statement above, you are assigning the
address of an int (arr[0]) to a pointer to an array. But arr[0] is an
int, not an array of ints.

Replace with:

p = &arr;

O'kay, dats fine.
if I change the declaration above as :

int (*p)[]; <-- pointer2array.c:12: error: invalid use of array with
unspecified bounds
int arr[10];
p = &arr;
for(i=0; i <= 12; i++){
*((*p) + i) = i;
printf("%d\n", p[0]);
}

compiler error!
what's the use of array index in the above declaration?
as i can go upto 12 or more...

-Neo


for(i=0; i <= 12; i++){ /* i <=12 delibrately written code */
*((*p) + i) = i;

printf("%d\n", p[0]);
}

return 0;
}

In the above program compiler is giving following warning

$gcc pointer2array.c
pointer2array.c: In function `main':
pointer2array.c:8: warning: assignment from incompatible pointer type

Why the warning?

O'kay and what is the use of int (*p)[10] type of declaration ?
Does the compiler perform any check on the array bounds?
lets say if i declare int arr[12]...


 
M

Mark McIntyre

if I change the declaration above as :

int (*p)[]; <-- pointer2array.c:12: error: invalid use of array with unspecified bounds

compiler error!

yes, its an error
what's the use of array index in the above declaration?

none - its an illegal construct
as i can go upto 12 or more...

only by invoking undefined behaviour....

Don't do that.
 
G

gooch

You can index up to whatever value you want. p[1000] is fine. The
result is going to be undefined. In most cases you would get a seg
fault but that may not be the case. You have to do the bounds checking
yourself.
 
R

Richard Bos

[ Using Google-Broken-Beta is not an excuse not to show any context.
Learn to use it to quote properly or get a real newsreader. Context
reinstated. ]
Neo said:
if I change the declaration above as :

int (*p)[]; <-- pointer2array.c:12: error: invalid use of array with
unspecified bounds
int arr[10];
p = &arr;
for(i=0; i <= 12; i++){
*((*p) + i) = i;
printf("%d\n", p[0]);
}

compiler error!
what's the use of array index in the above declaration?
as i can go upto 12 or more...

You can index up to whatever value you want. p[1000] is fine. The
result is going to be undefined.

I don't see how you can write those sentences together. The result of
p[10] and over are indeed going to be undefined, which is exactly why
such indices are _not_ fine.
In most cases you would get a seg fault but that may not be the case.

If you're lucky, you'll get a segfault. If you're unlucky, you won't see
the segfault, but your customer will. If you're _really_ unlucky,
neither of you will get a segfault, but your program will slowly
scribble over all your customer's data, and he'll sue you. Don't run
over the end of your arrays, not even when you think "it'll be safe,
because you'll get a segfault anyway".

Richard
 
G

gooch

"I don't see how you can write those sentences together. ....."

I am not saying it is a good thing or that you should do it, only that
it is not a legal operation.

"If you're lucky, you'll get a segfault. ....."

Again I am not suggesting he assume a segfault will occur, only that he
needs to do the bounds checking himself.
 
M

Mark McIntyre

On 3 Jan 2005 10:19:39 -0800, in comp.lang.c , "gooch"

(contextless stuff)

please read the VERY FIRST THING that richard said in his last post to you.
 
K

Keith Thompson

gooch said:
You can index up to whatever value you want. p[1000] is fine. The
result is going to be undefined. In most cases you would get a seg
fault but that may not be the case. You have to do the bounds checking
yourself.

(I presume p is an array with fewer than 1001 elements.)

p[1000] is not "fine" in any sense of the word. It is a serious error
that the implementation is not required to diagnose. This can
sometimes have the same visible results as something that's perfectly
legal, but the distinction is critical.

Incidentally, it's not true that "in most cases you would get a seg
fault". Attempting to access an array beyond its bounds is very
likely to refer to some other variable in your program, with
unpredictable results.

Your overall point, that you have to do your own bounds checking
because the implementation won't do it for you, is quite correct; I'm
just (over)reacting to your use of the word "fine".
 
S

Stan Milam

Jack said:
Hi Folks,


#include<stdio.h>
int main()
{
int (*p)[10];
int arr[10];
int i;

p = arr; /* <-- compiler warning */


The name of an array in an expression, other than when it is the
operand of the 'sizeof' or '&' operators, is converted to a pointer to
its first element. So in the statement above, you are assigning the
address of an int (arr[0]) to a pointer to an array. But arr[0] is an
int, not an array of ints.

Replace with:

p = &arr;

for(i=0; i <= 12; i++){ /* i <=12 delibrately written code */
*((*p) + i) = i;

printf("%d\n", p[0]);
}

return 0;
}

In the above program compiler is giving following warning

$gcc pointer2array.c
pointer2array.c: In function `main':
pointer2array.c:8: warning: assignment from incompatible pointer type

Why the warning?

O'kay and what is the use of int (*p)[10] type of declaration ?
Does the compiler perform any check on the array bounds?
lets say if i declare int arr[12]...


Okay, both of you are mistaken. int (*p)[10] is declaring an array of
10 pointers to function that return integers. Not quite the same thing
as either of you are talking about.
 
N

Neo

Stan Milam said:
Jack said:
Hi Folks,


#include<stdio.h>
int main()
{
int (*p)[10];
int arr[10];
int i;

p = arr; /* <-- compiler warning */


The name of an array in an expression, other than when it is the
operand of the 'sizeof' or '&' operators, is converted to a pointer to
its first element. So in the statement above, you are assigning the
address of an int (arr[0]) to a pointer to an array. But arr[0] is an
int, not an array of ints.

Replace with:

p = &arr;

for(i=0; i <= 12; i++){ /* i <=12 delibrately written code */
*((*p) + i) = i;

printf("%d\n", p[0]);
}

return 0;
}

In the above program compiler is giving following warning

$gcc pointer2array.c
pointer2array.c: In function `main':
pointer2array.c:8: warning: assignment from incompatible pointer type

Why the warning?

O'kay and what is the use of int (*p)[10] type of declaration ?
Does the compiler perform any check on the array bounds?
lets say if i declare int arr[12]...


Okay, both of you are mistaken. int (*p)[10] is declaring an array of 10
pointers to function that return integers. Not quite the same thing as
either of you are talking about.


pointers to function???
hmm.... its a pointer to arrary of 10 INTs!
-Neo
 
J

Jens.Toerring

Stan Milam said:
Okay, both of you are mistaken. int (*p)[10] is declaring an array of
10 pointers to function that return integers. Not quite the same thing
as either of you are talking about.

Sorry, but no.

int ( *p )[ 10 ];

is a pointer to an array of 10 ints. The parentheses here are needed to
distinguish it from

int *p[ 10 ];

which would be an array of 10 pointers to int. An array of 10 pointers
to functions that return int would be

int ( *p[ 10 ] )( );

Regards, Jens
 
L

Lawrence Kirby

Hi Folks,


#include<stdio.h>
int main()
{
int (*p)[10];
int arr[10];
int i;

p = arr; /* <-- compiler warning */
for(i=0; i <= 12; i++){ /* i <=12 delibrately written code */
*((*p) + i) = i;

printf("%d\n", p[0]);
}

return 0;
}

In the above program compiler is giving following warning

$gcc pointer2array.c
pointer2array.c: In function `main':
pointer2array.c:8: warning: assignment from incompatible pointer type

Why the warning?


Becuase you are trying to assign a value of type int * to a variable of
type int (*)[10]. C doesn't support implicit conversion between these
types. You could write

p = &arr;

but there isn't anything obvious to be gained over defining p as int *.
O'kay and what is the use of int (*p)[10] type of declaration ?

You could use this in something like the following

int arr2[5][10];
int (*p2)[10] = arr2;

Then accessing p2[x][y] will access the element arr2[x][y]
Does
the compiler perform any check on the array bounds? lets say if i
declare int arr[12]...

C doesn't require any sort of bounds checking from the compiler, and most
don't attempt to.

Lawrence
 
S

S.Tobias

Mark McIntyre said:
On Mon, 3 Jan 2005 14:01:44 +0530, in comp.lang.c , "Neo"
if I change the declaration above as :

int (*p)[]; <-- pointer2array.c:12: error: invalid use of array with unspecified bounds

compiler error!
yes, its an error

IMHO I think you're wrong here. `p' is simply a pointer to incomplete type
("array of int of unknown size").

The OP probably hadn't noticed that the error was at different line:
printf("%d\n", p[0]); //error
Exactly, the offending expression is p[0], because, it gets translated
to:
*(p + 0)
in which the summation cannot be evaluated because `*p' has an incomplete
type (however I fail to explain exactly why, because this expression doesn't
seem to violate any constraints at the "+" operator; could anyone help?).

The above expression can be corrected with:
(*p);
This is interesting, because we seem to apply indirection operator to
pointer to incomplete type (again, this is not a constraint violation,
however it doesn't work with pointers to incomplete struct type; could
someone help explain this please?); but here lvalue `*p', which is
of "array of int" type, is converted to "pointer to int" and points
to its first element, essentially same location as the array itself;
this rule seems to take precedence.


Type `int[]' is compatible with `int[10]' and `int[20]',
so `p' could be assigned an address of objects defined as:
int a[15];
int b[80];
double d[10]; //except this object
p = &a;
p = &b;
p = &d; //error
However, since `p' is a pointer to incomplete type, no arithmetic or
comparisons can be made with it.
I think one can describe `p' as a generic pointer to "arrays of int".
I don't know if it could be more useful than that.
only by invoking undefined behaviour....

Yes.
 
L

Lawrence Kirby

Mark McIntyre said:
On Mon, 3 Jan 2005 14:01:44 +0530, in comp.lang.c , "Neo"
if I change the declaration above as :

int (*p)[]; <-- pointer2array.c:12: error: invalid use of array with unspecified bounds

compiler error!
yes, its an error

IMHO I think you're wrong here. `p' is simply a pointer to incomplete type
("array of int of unknown size").

The OP probably hadn't noticed that the error was at different line:
printf("%d\n", p[0]); //error
Exactly, the offending expression is p[0], because, it gets translated
to:
*(p + 0)
in which the summation cannot be evaluated because `*p' has an incomplete
type (however I fail to explain exactly why, because this expression doesn't
seem to violate any constraints at the "+" operator; could anyone help?).


In both C90 and C99 the + operator requires a pointer operand to have a
pointer to an object type; an incomplete type is not an object type. This
is a constraint.

Lawrence
 
S

S.Tobias

In both C90 and C99 the + operator requires a pointer operand to have a
pointer to an object type; an incomplete type is not an object type. This
is a constraint.

Ah yes, thank you very much! I failed to check and understand the difference
between object and incomplete types (I thought object types were divided
into complete and incomplete; why is a long story).

I hope the rest of my previous analysis is mostly correct.


I think two things yet need an explanation.

1.
# 6.5.3.2 Address and indirection operators
# Constraints
# [...]
# 2 The operand of the unary * operator shall have pointer type.
a) This clearly allows pointers to incomplete types; why aren't they
generally forbidden?
b) Why can't I apply `*' to pointer to incomplete struct type?
struct notdefinedhereyet *p; //ptr to incomplete type
*p; //compiler refuses to generate code here, why?

2.
# 6.5.8 Relational operators
# [...]
# Constraints
# 2 One of the following shall hold:
# -- both operands have real type;
# -- both operands are pointers to qualified or unqualified
# versions of compatible object types; or
# -- both operands are pointers to qualified or unqualified
# versions of compatible incomplete types.
Why is one allowed to compare pointers either when both are pointers
to complete or both are pointers to incomplete compatible types?
Why a pair one being a pointer to complete and the other to incomplete
version of compatible type is excluded?
 
L

Lawrence Kirby

On Wed, 12 Jan 2005 00:00:17 +0000, S.Tobias wrote:

....
I think two things yet need an explanation.

1.
# 6.5.3.2 Address and indirection operators
# Constraints
# [...]
# 2 The operand of the unary * operator shall have pointer type.
a) This clearly allows pointers to incomplete types; why aren't they
generally forbidden?

Some reasons

1. &*p is valid. This might appear for example in macro expansions

2. Consider

extern int (*pa)[];
int *p = *pa;

b) Why can't I apply `*' to pointer to incomplete struct type?
struct notdefinedhereyet *p; //ptr to incomplete type
*p; //compiler refuses to generate code here, why?

Don't know, looks OK to me, as long as p points at a suitable object.
2.
# 6.5.8 Relational operators
# [...]
# Constraints
# 2 One of the following shall hold:
# -- both operands have real type;
# -- both operands are pointers to qualified or unqualified
# versions of compatible object types; or
# -- both operands are pointers to qualified or unqualified
# versions of compatible incomplete types.
Why is one allowed to compare pointers either when both are pointers
to complete or both are pointers to incomplete compatible types?
Why a pair one being a pointer to complete and the other to incomplete
version of compatible type is excluded?

Very good question. If nobody comes up with an answer maybe ask on
comp.std.c.

Lawrence
 
S

S.Tobias

Dereferencing a pointer yields an lvalue. Since incomplete type
doesn't fully describe an object, the result can't be a "good lvalue".
My personal feeling was that it would be more natural that
by default pointers to incomplete types be forbidden, except
in special cases.
1. &*p is valid. This might appear for example in macro expansions
extern int (*pa)[];
int *p = *pa;

Yes, these are those special cases, in which the dereferenced pointer
does not denote an lvalue (1. `*' is canceled by `&'; 2. result is
immediately converted to another type).

Don't know, looks OK to me, as long as p points at a suitable object.
Very good question. If nobody comes up with an answer maybe ask on
comp.std.c.

Thank you. I'll ask all of these questions again in c.s.c. in a few
days (if nobody...).
 
L

Lawrence Kirby

Dereferencing a pointer yields an lvalue.

Dereferencing a pointer can yield an lvalue. However the text of the
standard looks terminally broken in this respect. I should probably check
defects.

Essentially the problem is that the concept of lvalue is used in
constraint specifications (e.g. 6.5.16p2) which means that it is a
property that must be determinable at compile time, i.e. from static
analysis of the source code. C99 6.5.3.2p4 says

"The unary * operator denotes indirection. If the operand points to a
function, the result is a function designator; if it points to an object,
the result is an lvalue designating the object."

This is a specification for lvalue-ness based on a runtime property i.e.
whether the pointer points at an object or not, which makes it unworkable.
C99 6.3.2.1 says:

"An lvalue is an expression with an object type or an incomplete type
other than void;"

Note specifically that lvalues can have an incomplete type which is good
and correct. This of course has its own problems, apparently saying that
the expression 42 is an lvalue.
Since incomplete type
doesn't fully describe an object, the result can't be a "good lvalue".

But it can be an lvalue. For example

extern int a[];

a[0] = 1;

Here a has an incomplete type but because it is an lvalue is is still
converted to a pointer to its first element in an expression.
My personal feeling was that it would be more natural that
by default pointers to incomplete types be forbidden, except
in special cases.

I see no reason for this. If you allow void * you have to deal with
pointers to incomplete types one way or another. Using pointers to
incomplete structure types is a valid and important approach for
abstraction and information hiding.
1. &*p is valid. This might appear for example in macro expansions
extern int (*pa)[];
int *p = *pa;

Yes, these are those special cases, in which the dereferenced pointer
does not denote an lvalue (1. `*' is canceled by `&'; 2. result is
immediately converted to another type).

In the 2nd case *pa must be an lvalue for this to work.

....

Lawrence
 
K

Keith Thompson

Lawrence Kirby said:
Dereferencing a pointer can yield an lvalue. However the text of the
standard looks terminally broken in this respect. I should probably check
defects.

Yes, the standard's definition of "lvalue" is badly broken.

C90 6.2.2.1 says:

An _lvalue_ is an expression (with an object type or an incomplete
type other than void) that designates an object.

The problem with this definition is that, strictly speaking, you can't
determine at compilation time whether something is an lvalue or not.
Given a declaration

int *ptr;

the expression *ptr designates an object only if current the value of
ptr is non-null. Presumably the intent was that *ptr is an lvalue
regardless of the current value of ptr (and evaluating it invokes
undefined behavior if ptr happens to be null), but the definition
doesn't capture that intent.

C99 6.3.2.1 corrects this problem, but introduces a bigger one:

An _lvalue_ is an expression with an object type or an incomplete
type other than void; if an lvalue does not designate an object
when it is evaluated, the behavior is undefined.

This captures the idea that "*ptr" is an lvalue even if ptr==NULL --
but it also implies that 42 is an lvalue (because it's an expression
with an object type). It no longer says that an lvalue denotes an
object (which is what the concept of "lvalue" is all about), it merely
threatens undefined behavior if it doesn't.

The standard needs to say that an lvalue is an expression that either
denotes an object, or would denote an object if its subexpressions had
the right values. The trick is expressing this in sufficiently
rigorous standardese.

I raised this issue on comp.std.c a few months ago, but the discussion
wasn't productive.
 

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,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top