Lets see the memory layout first:
char arr[5][7][6]; here arr is a array of arrays of arrays.
It will be laid out into memory like following:
+--------------+
| | arr[0]
+--------------+
| | arr[1]
+--------------+
| | arr[2]
+--------------+
| | arr[3]
+--------------+
etc.
Now arr[i] is a array of arrays of char.
So a[i] will be like
+--------------+ a[i][0]
| |
+--------------+
| | a[i][1]
+--------------+
| | a[i][2]
+--------------+
| | a[i][3]
+--------------+
etc
Now arr[i][j] is a array of chars.
So
+--------------+
| | arr[i][j][0]
+--------------+
| | arr[i][j][1]
+--------------+
| | arr[i][j][2]
+--------------+
etc.
Compiler will make an entry in its symbol table with name arr and with the address of its first block and also keep track of the total size (5*6*7 = 210 bytes).
Now the expression
printf("%d\n", (&arr + 1) - &arr);
Its a pointer arithmetic. So it will bound to type of every symbols.
Lets see this in action.
(gdb) p &arr
$1 = (char (*)[5][7][6]) 0x7fffffffe160
You see the type of arr is pointer char (*)[5][6][7]
In other words its pointer to a array of arrays of arrays. Pointer arithmetic actually do relates to the type the pointer is pointed to. So its important what is the size of the type.
(gdb) p sizeof(char [5][7][6])
$2 = 210
So any pointer to the type char [5][6][7] will be incremented or decremented like follows:
&arr+1 => 0x7fffffffe160 +0xd2 => 0x7fffffffe232
and (&arr + 1) - &arr => 0x7fffffffe232 - 0x7fffffffe160=> 0xd2
Now it returns actually 0xd2. but for pointer arithmetic it means 1*sizeof(char [5][7][6]) => 1
Pointer arithmetic returns the number of sizeof(type) instead of actual byte offset.
You are getting correct result for
printf("%d\n", (char *)(&arr + 1) - (char *)&arr);
Because of the casting you are making it a char pointer. So the pointer arithmetic will use unit sizeof(char) which is of 1 byte size. And hence the output will be 210.
printf("%d\n", (unsigned)(arr + 1) - (unsigned)arr);
Here arr in a expression will decay to type char (*)[7][6] So its a pointer to a two dimensional array. The type its pointing to has a size 6*7 = 42. Thats what you are getting as result.
printf("%d\n", (unsigned)(p + 1) - (unsigned)p);
Here, p+1 - p will result in pointer arithmetic 1 * sizeof(char(*)[5][6][7]). So in pointer arithmetic, it should return 1. But because of your casting the results of to unsigned , it will abandon pointer arithmetic and use integer arithmetic. Because of using integer arithmetic, it will treat the pointer values of large numbers, so you will get the actual byte offset.