3

I was answering this question but when I tested the following code I got confused.

#include <iostream>

using namespace std;

int main()
{
        int **ptr;
        int arr[3][3];
        ptr =(int **) arr;
        for (int i=0;i<3;i++){
                for (int j=0;j<3;j++){
                        cout << &arr[i][j] << " =? ";
                        cout << &(ptr[i][j]) << endl;
                }

        }


        return 0;
}

But I get this ouput:

0x7fff5700279c =? 0
0x7fff570027a0 =? 0x4
0x7fff570027a4 =? 0x8
0x7fff570027a8 =? 0
0x7fff570027ac =? 0x4
0x7fff570027b0 =? 0x8
0x7fff570027b4 =? 0
0x7fff570027b8 =? 0x4
0x7fff570027bc =? 0x8

Why aren't they the same?

Community
  • 1
  • 1
0x90
  • 39,472
  • 36
  • 165
  • 245
  • 2
    Because you've used an evil cast: `ptr =(int **) arr;` `ptr` needs to be declared `int (*ptr)[3];`. – CB Bailey Mar 23 '13 at 13:44
  • See: http://stackoverflow.com/questions/3515045 – CB Bailey Mar 23 '13 at 13:47
  • 2
    `int*` and `int[]` are compatible, but you made a common but incorrect generalization when you thought that meant `int**` is compatible with `int[][]`. That's the reason you had to add a cast, casts are dangerous, avoid where possible. – john Mar 23 '13 at 14:53
  • @john so basically you can't declare a function for higher dimensions than 1D which handles arrays with variant size ? – 0x90 Mar 23 '13 at 15:12
  • 1
    Right. You can look into templates, but that is essentially writing multiple functions. Or you can change your calling code to use something other than arrays (such as std::vector). That is the usual solution. – john Mar 23 '13 at 15:15

3 Answers3

12
ptr =(int **) arr;

That is very bad - it involves a reinterpret_cast and results in undefined behaviour. The two types - an int[3][3] and an int** - are completely incompatible in terms of memory layout.

A 3-by-3 2D array is a contiguous block of memory that looks like this:

  0,0   0,1   0,2   1,0   1,1   1,2   2,0   2,1   2,2
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ int │ int │ int │ int │ int │ int │ int │ int │ int │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘

A pointer to pointer to int where each pointer points at the first element in an array looks like this:

┌─────┐
│     │ // The int**
└──╂──┘
   ┃
   ▼
┌─────┬─────┬┄
│     │     │   // An array of int*
└──╂──┴──╂──┴┄
   ┃     ┗━━━━━━━━━━┓
   ▼                ▼
┌─────┬─────┬┄   ┌─────┬─────┬┄
│ int │ int │    │ int │ int │    // Arrays of ints
└─────┴─────┴┄   └─────┴─────┴┄
  0,0   0,1        1,0   1,1

This involves two levels of indirection. The 2D array type doesn't have the array of pointers to go through. In addition, the arrays of ints in this int** case are not necessarily contiguous.

So think about when you do ptr[0], for example. What is the type of the expression? Since ptr is an int**, the type of ptr[0] is an int*. However, what is actually at the location ptr[0]? Not a pointer at all! Instead, there's an array of ints.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
10

int **ptr and an int arr[3][3] are different, since:

 -----------------------------------
|    C    |         Maths           |
 -----------------------------------
| ptr + 1 | ptr + sizeof(int*)      |
 -----------------------------------
| arr + 1 | arr + 3 * sizeof(int*)  |
 -----------------------------------

So you won't get the same results at all (moreover, ptr and arr may not have the same memory representation).

int (*ptr)[3] = arr;

will work, since only the first dimension of arr decays to a pointer.

md5
  • 23,373
  • 3
  • 44
  • 93
1

int** is a pointer to a pointer to int. Which means it is referring to an array of pointers. However, int[x][y] is an array of integers x by y in size. It is a single block of memory arranged into x rows of y columns (if you care to think of it that way.

To achieve what you want, you would have to collect the addresses of the columns and store them in the rows of your int** pointer.

int   arry[3][3];
int** ptr = malloc( sizeof(int*) * 3 );

for( int i = 0; i < 3; i++ )
   ptr[i] = arry[i];

for( int i = 0; i < 3; i++ )
    for( int j = 0; j < 3; j++ )
        printf( "%d -> %d\n", arry[i][j], ptr[i][j];

free( ptr );
K Scott Piel
  • 4,320
  • 14
  • 19