nigatoni
nigatoni

Reputation: 23

why i can cast from int** to int* with two-dimensional array, but not with pointer array?

why i can cast from int** to int* with two-dimensional array, but not with pointer array?

so for exmple why when i do this:

    int arr2d[3][3] = { { 1, 2, 3}, { 4, 5, 6}, { 7, 8, 9} };
    int* arr = (int*)arr2d;
    int i = 0;
    for (i = 0; i < 9; i++)
    {
        printf("%d ", arr[i]);
    }

it works and prints: 1 2 3 4 5 6 7 8 9

but when i do this:

    int arr1[] = { 11, 12 };
    int arr2[] = { 13, 14, 15, 16 };
    int arr3[] = { 17, 18, 19 };
    int* pArr[3] = { arr1, arr2, arr3 };
    int* pArr1d = (int*)pArr;
    for (i = 0; i < 9; i++)
    {
        printf("%d ", pArr1d[i]);
    }

it doesn't work and prints: 4192000 4191976 4191956 -858993460 -858993460 17 18 19 -858993460

Upvotes: 0

Views: 254

Answers (2)

4386427
4386427

Reputation: 44300

pArr is an array of 3 pointers to int.

When used in an expression pArr will be converted to a pointer to pointer to int and point to the initial element of the array (which is a pointer to int).

So when you do:

int* pArr1d = (int*)pArr;

You convert a "pointer to pointer to int" to a "pointer to int". The types are not compatible. Once you dereference the casted pointer, it's undefined behavior.

And when you print it you do two violation which is also undefined behavior.

  1. You print pointers as if they were integers.

  2. You access the array out of bounds.

Upvotes: 1

user15741790
user15741790

Reputation:

It is not int ** in the first case.

(int*)pArr is just a violent cast, not some constructor.

The first version warns with int *arr = arr2d; (no cast)

warning: 
initialization of 'int *' from incompatible pointer type 'int (*)[3]'

Incompatible maybe, but it is just that the arr2d has the ints in packs of 3, but back to back. Similar the inner braces are not necessary here (no gaps):

int arr2d[][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

Also the first dimension can be left out. int [][3] corresponds to int (*)[3].


The pointer version gives this warning with int* pArr1d = pArr;

warning: 
initialization of 'int *' from incompatible pointer type 'int **'

Dereferencing (pArr1d[i]) tries to access the i-th integer (of 9) at pArr1d --- but there are only 3 pointers there. So you can't simply flatten it out like above. (But now the three rows can have different sizes)


This works! The three arrays are one after the other (on the stack):

int arr1[] = { 11, 12 };
int arr2[] = { 13, 14, 15, 16 };
int arr3[] = { 17, 18, 19 };

for (int i = 0; i < 9; i++)
{
    printf("%d ", arr1[i]);
}

The debugger illustrates:

(gdb) p pArr
$13 = {0x7fffffffe87c, 0x7fffffffe890, 0x7fffffffe884}

(gdb) x/12 arr1
0x7fffffffe87c: 11      12      17      18
0x7fffffffe88c: 19      13      14      15
0x7fffffffe89c: 16      -6020   32767   -6000
(gdb) x/12 arr2
0x7fffffffe890: 13      14      15      16
0x7fffffffe8a0: -6020   32767   -6000   32767
0x7fffffffe8b0: -6012   32767   -1022695680     287912987
(gdb) x/12 arr3
0x7fffffffe884: 17      18      19      13
0x7fffffffe894: 14      15      16      -6020
0x7fffffffe8a4: 32767   -6000   32767   -6012

pArr holds three addresses - not integers.

Upvotes: 0

Related Questions