0

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

6
  • 3
    The answer is "undefined behavior" Commented May 2, 2021 at 18:39
  • The answer is "because you do have a sequence of ints starting at the addresses &arr2d. &arr2d[0] and &arr2d[0][0]), which are all identical. But you emphatically don't have one starting at the address &pArr or &parr[0], which are in turn identical": There, you have a sequence of addresses. The sequence of integers starts at the addresses contained in the elements of pArr: There is a sequence of ints at the address contained in pArr[0]. Commented May 2, 2021 at 18:46
  • @4386427 While correct, it is just "because it is wrong" in other words, which must have been clear to the OP before. Their question is why. (Ah, I see you are trying an answer, that's good.) Commented May 2, 2021 at 18:49
  • 1
    @Peter-ReinstateMonica Why...! For several reasons... read my answer Commented May 2, 2021 at 18:51
  • that you can cast something in C doesn't automatically mean it is a good thing. Commented May 2, 2021 at 18:59

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

The cast is not undefined, but using the result of the cast to try and access int objects is
@M.M Updates the wording
0

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.

2 Comments

Your last example causes undefined behaviour by reading off the end of an array
yes, the exclamation mark is a bit short as comment, And the order is wrong. pArr has got it right: e87c, e890, e884 (arr2 and arr3 switched "places"). Well I wanted to illustrate with gdb, then I saw the layout and tried...at home. Don't. Arr1 could be last, to begin with. And arr1-3 "normally" are apart - so collecting their addresses in pArr is necessary.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.