Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   Re: Two dimensional pointers and Two dimensional arrays (http://www.velocityreviews.com/forums/t276831-re-two-dimensional-pointers-and-two-dimensional-arrays.html)

 Icosahedron 08-18-2003 08:33 AM

Re: Two dimensional pointers and Two dimensional arrays

> Hello,
> I know this is a pretty old topic, and must have been
> discussed time and again. I want to the exact reason why a
> two d array(ex. int arr[20][10]) can't be accessed using a
> two d pointer(int **p). In the posts which I have gone thru,
> state that the two d array, arr, is an array of arrays. So,
> what arr actually points to is the first element of the 2 d
> array, this element being an array of 10 integers.
> The thing which is not clear is: Consider int b[10], and
> int * q. Here b is an array of 10 integers,and can be
> accessed using the pointer q.
> i.e
>
> int b[10],* q;
> q=b;
> cout<<q[8]<<endl;
>
> is perfectly legal.

Yes. The equivalent code, boiled down to pointer arithmetic
psuedo C code is similar (though not exact). It comes down
to something like:

((char*)q)+8*sizeof(int);

> Then in the case of 2 d array, arr[i] is equivalent to b,
> since both are actually 1d array of 10 int's. So if b can be
> accessed using a 1d pointer, so can arr[i]?
> And arr is a pointer to arr[0], so the question why can't a
> be accessed using p i.e
>
> int arr[20][10], **p;
> p=(int**)arr;
> cout<<p[1][1]<<endl;
> This cores.

The equivalent hacked pointer arithmetic code for using arr
in cout << arr[1][1] << endl is something like:

((char*) arr)+(1*10)+1

whereas for p it's

*((char *) p)+1 // notice the * in front of p and missing (1*10)

The compiler generates code such that it thinks p is a
separate array of 20 pointers to 10 element arrays, whereas
the compiler knows that arr is actually 200 contiguous
elements referenced by two indices of relative multipliers.

Sorry my psuedo code isn't prettier, but the best way to
"see" it would be to look at the generated assembly.

Also, that's why the cast to (int**) was needed on the
second example and the first didn't require a cast.

Hope this helps.

Jay

 Vivek 08-18-2003 01:45 PM

Re: Two dimensional pointers and Two dimensional arrays

((char*)q)+8*sizeof(int);
The equivalent code should be:
(*q)+8*sizeof(int), I suppose, since (char*)q just type casts it as a char pointer.
>
>
> The equivalent hacked pointer arithmetic code for using arr
> in cout << arr[1][1] << endl is something like:
>
> ((char*) arr)+(1*10)+1
>
> whereas for p it's
>
> *((char *) p)+1 // notice the * in front of p and missing (1*10)
>

Even here, should n't it be
*(*(p+1)+1)
But the question is: why does the program core?

> The compiler generates code such that it thinks p is a
> separate array of 20 pointers to 10 element arrays, whereas
> the compiler knows that arr is actually 200 contiguous
> elements referenced by two indices of relative multipliers.
>
> Sorry my psuedo code isn't prettier, but the best way to
> "see" it would be to look at the generated assembly.
>
> Also, that's why the cast to (int**) was needed on the
> second example and the first didn't require a cast.
>
> Hope this helps.
>
> Jay

 John Harrison 08-19-2003 05:36 AM

Re: Two dimensional pointers and Two dimensional arrays

> "John Harrison" <john_andronicus@hotmail.com> wrote in message

news:<bhqmvb\$26f22\$1@ID-196037.news.uni-berlin.de>...
> > Because you are forcing the compiler to interpret integers as pointers.
> >
> > p is pointing at an array of integers, when *(*(p + 1)+1) executes

compiler
> > takes the bit patterns for an integer (or two) and interprets them as a
> > pointer.
> >
> > john

>
> But when I replace p with arr, i.e
> cout<<*(*(arr+1)+1)<<endl;
> it does n't core. And it does give the expected result(value of
> arr[1][1])
> Then does n't this mean that arr is indeed stored as a pointer to
> pointer to integer.

No, it doesn't, try this

cout << a[1] << &a[1][0];

You'll get the same address. Also that fact that your cast p = (int**)a
doesn't work also proves this. In fact the very fact that you need a cast
proves this.

Lets try again with this

int a[2][2];

In memory

| a00 | a01| a10 | a11 |

cout << a[1][1]

compiler generates

*(*(a + 1) + 1)

In this context a has type int (*)[2] (decay of array type to equivalent
pointer type), so a + 1, is a expression of type int (*)[2] which points at
a10. *(a + 1) is therefore an expression of type int[2] which points at a10.
When you take the address of an array type the pointer doesn't change, when
you dereference a pointer to an array the pointer doesn't change, maybe this
is what you are missing. Then you get to a11 in the usual way.

Now try this

int a[2][2];
int** p = (int**)a;
cout << p[1][1]

compiler generates

*(*(p + 1) + 1)

p has type int** and is pointer to a00, so p + 1 has type int** and is
pointing to a01 (assuming that sizeof(int*)==sizeof(int)). Therefore *(a +
1) interprets the integer a01 as a pointer and dereferences it. Crash! Note
the difference from the array case. There was no real deference at that
stage.

john

 Vivek 08-20-2003 05:23 AM

Re: Two dimensional pointers and Two dimensional arrays

"John Harrison" <john_andronicus@hotmail.com> wrote in message news:<bhsd02\$2f6gl\$1@ID-196037.news.uni-berlin.de>...
>
> compiler generates
>
> *(*(a + 1) + 1)
>
> In this context a has type int (*)[2] (decay of array type to equivalent
> pointer type), so a + 1, is a expression of type int (*)[2] which points at
> a10. *(a + 1) is therefore an expression of type int[2] which points at a10.
> When you take the address of an array type the pointer doesn't change, when
> you dereference a pointer to an array the pointer doesn't change, maybe this
> is what you are missing. Then you get to a11 in the usual way.
>

Thanks a lot for the explanation. Now its very clear.
But one thing which is not clear is:
If I want to visualise this, &a is same as a, and *a is same as a,
then does this mean, * & operators has different meaning when applied
on an array? Because if we go by the definition of '*' operator it
should give the content of the address stored in a, which is a10(the
integer value). And, **a gives the integer value a10.

> Now try this
>
> int a[2][2];
> int** p = (int**)a;
> cout << p[1][1]
>
> compiler generates
>
> *(*(p + 1) + 1)
>
> p has type int** and is pointer to a00, so p + 1 has type int** and is
> pointing to a01 (assuming that sizeof(int*)==sizeof(int)).

Here why does sizeof(int*) come into picture? Since for evaluating
p+1, the thing which is considered is the datatype to which p points
to, which is int in this case.

>Therefore *(a + 1) interprets the integer a01 as a pointer and

dereferences it. Crash! Note
> the difference from the array case. There was no real deference at that
> stage.
>
> john

 John Harrison 08-20-2003 05:40 AM

Re: Two dimensional pointers and Two dimensional arrays

> "John Harrison" <john_andronicus@hotmail.com> wrote in message

news:<bhsd02\$2f6gl\$1@ID-196037.news.uni-berlin.de>...
> >
> > compiler generates
> >
> > *(*(a + 1) + 1)
> >
> > In this context a has type int (*)[2] (decay of array type to equivalent
> > pointer type), so a + 1, is a expression of type int (*)[2] which points

at
> > a10. *(a + 1) is therefore an expression of type int[2] which points at

a10.
> > When you take the address of an array type the pointer doesn't change,

when
> > you dereference a pointer to an array the pointer doesn't change, maybe

this
> > is what you are missing. Then you get to a11 in the usual way.
> >

>
> Thanks a lot for the explanation. Now its very clear.
> But one thing which is not clear is:
> If I want to visualise this, &a is same as a, and *a is same as a,
> then does this mean, * & operators has different meaning when applied
> on an array?

I think you mean & applied to an array and * applied to a pointer to array,
if a is an array, then *a is its first element (i.e. a[0]). Try this

int a[10];
int (*pa)[10] = &a;

cout << a << pa << *pa;

All three pointers should have the same value. Basically an array can be
regarded as a pointer to its first element, but a pointer to an array is
also a pointer to its first element (what else could it be). Arrays are not
like other variables, its quite ugly, but its how C has always been.

> Because if we go by the definition of '*' operator it
> should give the content of the address stored in a, which is a10(the
> integer value). And, **a gives the integer value a10.
>
> > Now try this
> >
> > int a[2][2];
> > int** p = (int**)a;
> > cout << p[1][1]
> >
> > compiler generates
> >
> > *(*(p + 1) + 1)
> >
> > p has type int** and is pointer to a00, so p + 1 has type int** and is
> > pointing to a01 (assuming that sizeof(int*)==sizeof(int)).

>
> Here why does sizeof(int*) come into picture? Since for evaluating
> p+1, the thing which is considered is the datatype to which p points
> to, which is int in this case.

No, the datatype of p is int*. p has type int** so p is pointing at int*.

john

 Jon Bell 08-20-2003 01:59 PM

Re: Two dimensional pointers and Two dimensional arrays

>My question was: in memory how shall this be stored?
>
>int a[10][20];

This allocates a collection of 200 ints, in a single contiguous chunk of
memory. Their sequence is a[0][0], a[0][1], a[0][2], ..., a[0][9],
a[1][0], a[1][1], etc.

>The values of a, *a and **a as printed are:
>
>a=-4262140 *a=-4262140 and **a=1
>
>What does this mean?

displays pointer values as decimal integers. My compiler displays them in
hexadecimal. So that's just a display format issue. Here's how to
interpret what you're seeing:

'a[10][20]' is an array of 10 arrays, each of which contains 20 ints.

'a' is a pointer to the first element of the "outer" array. That is, it
contains the address of the first of the "inner" arrays.

'*a' is the first element of the "outer" array, that is, it's the first
"inner" array. When you display it, it decays into a pointer to the first
element of that array, which is of course also the same location as the
beginning of the "outer" array. So it's the same address that 'a' gives
you.

'**a' is the first element of the first "inner" array. It's an int, which
you apparently have initialized to contain the value 1.

--
Jon Bell <jtbellap8@presby.edu> Presbyterian College
Dept. of Physics and Computer Science Clinton, South Carolina USA

 Jon Bell 08-20-2003 02:06 PM

Re: Two dimensional pointers and Two dimensional arrays

Just to clarify a bit and make my terminology consistent:

In article <HJx87s.Mvo@presby.edu>, Jon Bell <jtbellap8@presby.edu> wrote:
>
>'a[10][20]' is an array of 10 arrays, each of which contains 20 ints.
>
>'a' is a pointer to the first element of the "outer" array. That is, it
>contains the address of the first of the "inner" arrays.

Change the paragraph above to read:

'a' decays into a pointer to the first element of the "outer" array. That
is, when you use it as an identifier without the subscript operator [], it
gives you the address of the first of the "inner" arrays.

>'*a' is the first element of the "outer" array, that is, it's the first
>"inner" array. When you display it, it decays into a pointer to the first
>element of that array, which is of course also the same location as the
>beginning of the "outer" array. So it's the same address that 'a' gives
>you.
>
>'**a' is the first element of the first "inner" array. It's an int, which
>you apparently have initialized to contain the value 1.

--
Jon Bell <jtbellap8@presby.edu> Presbyterian College
Dept. of Physics and Computer Science Clinton, South Carolina USA

 John Harrison 08-20-2003 06:58 PM

Re: Two dimensional pointers and Two dimensional arrays

> "John Harrison" <john_andronicus@hotmail.com> wrote in message

news:<bhv1q4\$3cqv8\$1@ID-196037.news.uni-berlin.de>...
> > An array can be regarded as a pointer to it first element, but a pointer

to
> > an array HAS THE SAME VALUE as a pointer to the first element.
> >
> > john

> My question was: in memory how shall this be stored?
>
> int a[10][20];
>
> The values of a, *a and **a as printed are:
>
> a=-4262140 *a=-4262140 and **a=1
>
> What does this mean?
> If I go by the *a's value, does n't it mean value '-4262140' shall be

I don't know how many times I can tell you this, multidimensional arrays are
not stored as arrays of pointers in C++.

> Or is it just the way that C++ compiler
> interprets *a to be same as a?

a and *a are both arrays, these are converted to pointers and printed
as -4262140. The are both converted to the same pointer value because the
array *a (or a[0], its the same thing) starts at the same place in memory as
the array a.

**a is an int, and is printed as such.

john

 Vivek 08-21-2003 05:15 AM

Re: Two dimensional pointers and Two dimensional arrays

> > Or is it just the way that C++ compiler
> > interprets *a to be same as a?

>
> a and *a are both arrays, these are converted to pointers and printed
> as -4262140. The are both converted to the same pointer value because the
> array *a (or a[0], its the same thing) starts at the same place in memory as
> the array a.
>
> **a is an int, and is printed as such.
>
> john

Thanks a lot for all. Its clear now.

Thank you John for bearing with me.

 All times are GMT. The time now is 07:38 AM.