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.