# whats wrong with this pointer operation?

Discussion in 'C Programming' started by =?ISO-8859-1?Q?Martin_J=F8rgensen?=, Apr 20, 2006.

1. ### =?ISO-8859-1?Q?Martin_J=F8rgensen?=Guest

Hi,

"C primer plus" p.382:

Suppose we have this declaration:

int (*pa)[3];
int ar1[2][3];
int ar2[3][2];
int **p2;

Then this is okay:
pa = ar1; // both pointer-to-int[3]

But these are not:
pa = ar2; // why not?
p2 = ar2; // why not?

ar1 and ar2 must be the same type: pointer-to-pointer-to-int (or
pointer-to-int-array).

And pa must be a pointer to int[3]-array... So in my opinion pa = ar2
should work but the book says "not valid"...? I also think that p2 = ar2
should work, but that seems wrong according to the book?

Best regards / Med venlig hilsen
Martin Jørgensen

--
---------------------------------------------------------------------------
Home of Martin Jørgensen - http://www.martinjoergensen.dk

=?ISO-8859-1?Q?Martin_J=F8rgensen?=, Apr 20, 2006

2. ### pinkfogGuest

Martin Jørgensen wrote:
> Hi,
>
> "C primer plus" p.382:
>
> Suppose we have this declaration:
>
> int (*pa)[3];

you can give a example to understand it.This expression means:
an 2_D array: int* pa_0 ,int * pa_1 ,int* pa_2 ,that is to say: in the
2-D array form ,there are integers of size_t rows and 3 colums .
> int ar1[2][3];
> int ar2[3][2];
> int **p2;

So ar1: 2 rows and 3 colums
ar2: 3 rows and 2 colums
p2: unknown size
>
> Then this is okay:
> pa = ar1; // both pointer-to-int[3]

Right. The assignment makes pa a 2*3 2_D array.
>
>
> But these are not:
> pa = ar2; // why not?
> p2 = ar2; // why not?
>

Wrong. ar2 and pa are not of the same size.
>
> ar1 and ar2 must be the same type: pointer-to-pointer-to-int (or
> pointer-to-int-array).
>
> And pa must be a pointer to int[3]-array... So in my opinion pa = ar2
> should work but the book says "not valid"...? I also think that p2 = ar2
> should work, but that seems wrong according to the book?

Hope this can help a little.
----------------------pinkfog-----------------------

pinkfog, Apr 20, 2006

3. ### Keith ThompsonGuest

Martin Jørgensen <> writes:
> "C primer plus" p.382:
>
> Suppose we have this declaration:
>
> int (*pa)[3];
> int ar1[2][3];
> int ar2[3][2];
> int **p2;
>
>
> Then this is okay:
> pa = ar1; // both pointer-to-int[3]

Right. ar1 is an array[2] of array[3] of int; it decays to a pointer
to array[3] of int. Since pa is explicitly pointer to array[3] of
int, the types match.

> But these are not:
> pa = ar2; // why not?
> p2 = ar2; // why not?
>
> ar1 and ar2 must be the same type: pointer-to-pointer-to-int (or
> pointer-to-int-array).

No. Arrays are not pointers. Pointers are not arrays. There is no
pointer-to-pointer here.

The declaration
int ar2[3][2];
declares ar2 as an array[3] of array[2] of int. The memory allocated
for it is enough to hold 3*2 int objects (6 * sizeof(int)). The name
ar2, in most contexts, decays to a pointer to array[2] of int; this
is a pointer value, not a pointer object.

This declaration does *not* create a pointer-to-pointer. No space is
allocated for any pointer object. A pointer-to-pointer and a
pointer-to-array are two different things; neither may be converted to
the other. A pointer *value* may be created when the name ar2 is used
in an expression, but only a pointer to array[2] of int, not any kind
of pointer-to-pointer.

In
pa = ar2;
pa is of type pointer to array[3] of int, and ar2 is of type array[3]
of array[2] of int, which decays to pointer to array[2] of int.
Though both sides are pointers to array of int, the types don't match
because they're pointers to arrays of different lengths.

In
p2 = ar2;
p2 is a pointer to pointer to int, and as we've seen, ar2 is not, and
does not decay into, a pointer to pointer. Again, the types are
incompatible.

"Pointers and Arrays".

--
Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.

Keith Thompson, Apr 20, 2006
4. ### =?ISO-8859-1?Q?Martin_J=F8rgensen?=Guest

Keith Thompson wrote:
> Martin Jørgensen <> writes:
>
>>"C primer plus" p.382:
>>
>>Suppose we have this declaration:
>>
>>int (*pa)[3];
>>int ar1[2][3];
>>int ar2[3][2];
>>int **p2;
>>
>>
>>Then this is okay:
>>pa = ar1; // both pointer-to-int[3]

>
>
> Right. ar1 is an array[2] of array[3] of int; it decays to a pointer
> to array[3] of int. Since pa is explicitly pointer to array[3] of
> int, the types match.

Uh, yes... I forgot to look at the column-size...

>>But these are not:
>>pa = ar2; // why not?
>>p2 = ar2; // why not?
>>
>>ar1 and ar2 must be the same type: pointer-to-pointer-to-int (or
>>pointer-to-int-array).

>
>
> No. Arrays are not pointers. Pointers are not arrays. There is no
> pointer-to-pointer here.

Ofcourse...

> The declaration
> int ar2[3][2];
> declares ar2 as an array[3] of array[2] of int. The memory allocated
> for it is enough to hold 3*2 int objects (6 * sizeof(int)). The name
> ar2, in most contexts, decays to a pointer to array[2] of int; this
> is a pointer value, not a pointer object.

Thanks a lot... I just have to make sure: What exactly do you mean by:

1) Pointer value

2) Pointer object

What's the difference? C isn't "object-oriented" as in C++ so I just
want to make sure I understand the difference...

> This declaration does *not* create a pointer-to-pointer. No space is
> allocated for any pointer object. A pointer-to-pointer and a
> pointer-to-array are two different things; neither may be converted to
> the other. A pointer *value* may be created when the name ar2 is used
> in an expression, but only a pointer to array[2] of int, not any kind
> of pointer-to-pointer.

Thanks... Makes sense.

> In
> pa = ar2;
> pa is of type pointer to array[3] of int, and ar2 is of type array[3]
> of array[2] of int, which decays to pointer to array[2] of int.

Sounds to me like: I've read something about that there is a similarity
between declaring array[3][2] and declaring array[][2] in a function

Is that what you mean by "decaying into"?

> Though both sides are pointers to array of int, the types don't match
> because they're pointers to arrays of different lengths.

It's only the column-size that must match, isn't it?

> In
> p2 = ar2;
> p2 is a pointer to pointer to int, and as we've seen, ar2 is not, and
> does not decay into, a pointer to pointer. Again, the types are
> incompatible.
>
> If you haven't already, read section 6 of the comp.lang.c FAQ,
> "Pointers and Arrays".

I think I've read it a couple of times... But I just forgot something
which I now remember...

It isn't that hard for me to understand... That's why I only got a few
comments here - I agree with what you wrote, after reading it...

Best regards / Med venlig hilsen
Martin Jørgensen

--
---------------------------------------------------------------------------
Home of Martin Jørgensen - http://www.martinjoergensen.dk

=?ISO-8859-1?Q?Martin_J=F8rgensen?=, Apr 20, 2006
5. ### Mark McIntyreGuest

On Thu, 20 Apr 2006 16:27:17 +0200, in comp.lang.c , Martin Jørgensen
<> wrote:

>Thanks a lot... I just have to make sure: What exactly do you mean by:
>
>1) Pointer value
>
>2) Pointer object

int x=3;

x is an int object

3 is its int value

Same thing with pointers.

>Sounds to me like: I've read something about that there is a similarity
>between declaring array[3][2] and declaring array[][2] in a function
>
>Is that what you mean by "decaying into"?

No, but its related.
When an array is passed to a function, it is "decayed" into a pointer
to its first element. Inside the function, there is no array, only the
pointer.
The example you give is a consequence of this. Since the array decays
into a pointer, there is no use declaring its (first) dimension.

>> Though both sides are pointers to array of int, the types don't match
>> because they're pointers to arrays of different lengths.

>
>It's only the column-size that must match, isn't it?

Please don't think of it as columns and rows - its not like that. What
will you do when you get to 3, 4 or 5 dimensions?

And AFAIK the types will only match if all dimensions match.

Mark McIntyre
--
"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan

Mark McIntyre, Apr 20, 2006
6. ### Default UserGuest

Martin Jørgensen wrote:

> Keith Thompson wrote:
> >Martin Jørgensen <> writes:
> >
> > > "C primer plus" p.382:
> > >
> > > Suppose we have this declaration:
> > >
> > > int (*pa)[3];
> > > int ar1[2][3];
> > > int ar2[3][2];
> > > int **p2;
> > >
> > >
> > > Then this is okay:
> > > pa = ar1; // both pointer-to-int[3]

> >
> >
> > Right. ar1 is an array[2] of array[3] of int; it decays to a
> > pointer to array[3] of int. Since pa is explicitly pointer to
> > array[3] of int, the types match.

>
> Uh, yes... I forgot to look at the column-size...
>
> > > But these are not:
> > > pa = ar2; // why not?
> > > p2 = ar2; // why not?
> > >
> > > ar1 and ar2 must be the same type: pointer-to-pointer-to-int (or
> > > pointer-to-int-array).

> >
> >
> > No. Arrays are not pointers. Pointers are not arrays. There is no
> > pointer-to-pointer here.

>
> Ofcourse...
>
> > The declaration
> > int ar2[3][2];
> > declares ar2 as an array[3] of array[2] of int. The memory
> > allocated for it is enough to hold 3*2 int objects (6 *
> > sizeof(int)). The name ar2, in most contexts, decays to a pointer
> > to array[2] of int; this is a pointer value, not a pointer object.

>
> Thanks a lot... I just have to make sure: What exactly do you mean by:
>
> 1) Pointer value
>
> 2) Pointer object
>
> What's the difference? C isn't "object-oriented" as in C++ so I just
> want to make sure I understand the difference...

From the draft standard:

3.15
[#1] object
region of data storage in the execution environment, the
contents of which can represent values

[#2] NOTE When referenced, an object may be interpreted as
having a particular type; see 6.3.2.1.

So pointer objects can hold pointer values.

> Sounds to me like: I've read something about that there is a
> similarity between declaring array[3][2] and declaring array[][2] in

The leftmost dimension isn't necessary in function declarations,
because you can't pass arrays, only pointers to the first element.
That's why you can have:

void func(int *p);
void func(int p[]);

They both mean the same thing. In the case of a mult-dimension array,
the first element is another array.

> Is that what you mean by "decaying into"?

In most contexts, the name of an array is converted to a pointer to the
first element. Exceptions include with the array name is used with the
sizeof operator or the address-of (&) operator.

> > Though both sides are pointers to array of int, the types don't
> > match because they're pointers to arrays of different lengths.

>
> It's only the column-size that must match, isn't it?

Everything but the left-most dimension. So if it was a three-D array,
the two right dimensions would have to match.

Brian

Default User, Apr 20, 2006
7. ### peteGuest

Mark McIntyre wrote:
>
> On Thu, 20 Apr 2006 16:27:17 +0200, in comp.lang.c , Martin Jørgensen
> <> wrote:
>
> >Thanks a lot... I just have to make sure:
> >What exactly do you mean by:
> >
> >1) Pointer value
> >
> >2) Pointer object

>
> int x=3;
>
> x is an int object
>
> 3 is its int value
>
> Same thing with pointers.

(&x) is an example of a pointer value
that is not a pointer object.

--
pete

pete, Apr 20, 2006
8. ### Keith ThompsonGuest

Martin Jørgensen <> writes:
> Keith Thompson wrote:
>> Martin Jørgensen <> writes:

[...]
>> The declaration
>> int ar2[3][2];
>> declares ar2 as an array[3] of array[2] of int. The memory allocated
>> for it is enough to hold 3*2 int objects (6 * sizeof(int)). The name
>> ar2, in most contexts, decays to a pointer to array[2] of int; this
>> is a pointer value, not a pointer object.

>
> Thanks a lot... I just have to make sure: What exactly do you mean by:
>
> 1) Pointer value
>
> 2) Pointer object
>
> What's the difference? C isn't "object-oriented" as in C++ so I just
> want to make sure I understand the difference...

Right, the term "object" in C has nothing to do with "object-oriented"
anything. The standard's definition of "object" is a "region of data
storage in the execution environment, the contents of which can
represent values" (C99 3.14).

Loosely speaking, it's nearly the same thing as a variable. An object
can also be a component of another object, or the chunk of memory
allocated by malloc(). (The standard doesn't define the term
"variable".)

A value is the result of evaluating an expression. It isn't
necessarily stored anywhere; it's a transient thing that exists only
while the expression is being evaluated, unless it's stored in an
object.

An object name is an expression; the value of the expression is the
value that was stored in the object.

A pointer object is an object of pointer type; the value of a pointer
object is a pointer value, also known as an address.

(There's some controversy in this area. Some people feel strongly
that the unadorned word "pointer" should refer only to a pointer
object, never to a value -- but the standard, like it or not, talks
about functions returning pointers. I usually try to avoid the issue
by referring explicitly to pointer objects and pointer values.)

>[...]

>> In
>> pa = ar2;
>> pa is of type pointer to array[3] of int, and ar2 is of type array[3]
>> of array[2] of int, which decays to pointer to array[2] of int.

>
> Sounds to me like: I've read something about that there is a
> similarity between declaring array[3][2] and declaring array[][2] in a
>
> Is that what you mean by "decaying into"?

No, that's something different (but related, I suppose).

A function can't have a parameter of array type. You can declare
something that *looks* like an array parameter:
void foo(char param[]);
but, because of a special-case rule, that's exactly the same as:
void foo(char *param);
The same is true if you specify the length of the aray:
void foo(char param[42]);
The length is just quietly ignored.

The intent of the rule is to allow you to indicate that the argument
is expected to be an array (which will decay to a pointer), but in my
opinion this rule causes more problems than it solves.

void bar(int array[3][2]);
vs.
void bar(int array[][2]);
is just a special case of this, where the array's element type happens
to be another array type.

But when I used the phrase "decaying into", I was referring to the
implicit conversion of array expressions to pointer type.

In most contexts, an expression of array type (such as the name of a
declared array object) is implicitly converted to a pointer to the
array's first element. The exceptions are: (1) the argument to the
"sizeof" operator, (2) the argument to the "&" operator, and (3) a
string literal used in an initialize an array.

>> Though both sides are pointers to array of int, the types don't match
>> because they're pointers to arrays of different lengths.

>
> It's only the column-size that must match, isn't it?

In this case, yes (of course the element type must match as well).
But a better way to think about it is that the types must match, after
any implicit conversions have been applied. A two-dimensional array
is just an array of arrays. There are no special rules for
multi-dimensional arrays; their behavior is determined entirely by the
rules for one-dimensional arrays, including implicit conversions to
pointers.

--
Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.

Keith Thompson, Apr 20, 2006
9. ### Keith ThompsonGuest

Mark McIntyre <> writes:
> On Thu, 20 Apr 2006 16:27:17 +0200, in comp.lang.c , Martin Jørgensen
> <> wrote:

[...]
>>Sounds to me like: I've read something about that there is a similarity
>>between declaring array[3][2] and declaring array[][2] in a function
>>
>>Is that what you mean by "decaying into"?

>
> No, but its related.
> When an array is passed to a function, it is "decayed" into a pointer
> to its first element. Inside the function, there is no array, only the
> pointer.
> The example you give is a consequence of this. Since the array decays
> into a pointer, there is no use declaring its (first) dimension.

Right. And this is just one case of a more general rule, having
nothing to do with function calls. An expression of array type is (in
most contexts) implicitly converted to a pointer to its first element.
This applies whether it's a function argument, the right hand side of
an assignment, or the operand of a "+" operator (with the exceptions

It even applies to the array indexing operator. For example:

int arr[10];
int x = arr[5];

The indexing operator takes two operands, a pointer and an integer.
If one of its operands is the name of an array, that operand is
implicitly converted to a pointer. An indexing operator "x[y]" is by
definition equivalent to "*(x+y)". It's most commonly used on arrays,
of course, but that's just a special case; it's defined to work on
pointers.

--
Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.

Keith Thompson, Apr 20, 2006