Re: Two dimensional pointers and Two dimensional arrays

Discussion in 'C++' started by Icosahedron, Aug 18, 2003.

  1. Icosahedron

    Icosahedron Guest

    >"Vivek" <> wrote in message
    news:...
    > 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 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?
    > 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
     
    Icosahedron, Aug 18, 2003
    #1
    1. Advertising

  2. Icosahedron

    Vivek Guest

    ((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
     
    Vivek, Aug 18, 2003
    #2
    1. Advertising

  3. "Vivek" <> wrote in message
    news:...
    > "John Harrison" <> wrote in message

    news:<bhqmvb$26f22$-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
     
    John Harrison, Aug 19, 2003
    #3
  4. Icosahedron

    Vivek Guest

    "John Harrison" <> wrote in message news:<bhsd02$2f6gl$-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
     
    Vivek, Aug 20, 2003
    #4
  5. "Vivek" <> wrote in message
    news:...
    > "John Harrison" <> wrote in message

    news:<bhsd02$2f6gl$-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
     
    John Harrison, Aug 20, 2003
    #5
  6. Icosahedron

    Jon Bell Guest

    In article <>,
    Vivek <> wrote:
    >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?


    The address comes out as negative because your compiler apparently
    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 <> Presbyterian College
    Dept. of Physics and Computer Science Clinton, South Carolina USA
     
    Jon Bell, Aug 20, 2003
    #6
  7. Icosahedron

    Jon Bell Guest

    Just to clarify a bit and make my terminology consistent:

    In article <>, Jon Bell <> 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 <> Presbyterian College
    Dept. of Physics and Computer Science Clinton, South Carolina USA
     
    Jon Bell, Aug 20, 2003
    #7
  8. "Vivek" <> wrote in message
    news:...
    > "John Harrison" <> wrote in message

    news:<bhv1q4$3cqv8$-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
    > stored at address -4262140?


    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
     
    John Harrison, Aug 20, 2003
    #8
  9. Icosahedron

    Vivek Guest

    > > 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.
     
    Vivek, Aug 21, 2003
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alf P. Steinbach
    Replies:
    0
    Views:
    436
    Alf P. Steinbach
    Aug 18, 2003
  2. John Harrison
    Replies:
    4
    Views:
    6,927
    Default User
    Aug 19, 2003
  3. Richard Hayden

    C multi-dimensional arrays and pointers

    Richard Hayden, Nov 1, 2004, in forum: C Programming
    Replies:
    4
    Views:
    982
    Dave Thompson
    Nov 8, 2004
  4. Kev Jackson
    Replies:
    2
    Views:
    114
  5. Wirianto Djunaidi
    Replies:
    2
    Views:
    203
    Wirianto Djunaidi
    Apr 29, 2008
Loading...

Share This Page