1

Please explain the output of first and last printf statements. I think they should give the same output.

int main()
{
   char arr[5][7][6];
   char (*p)[5][7][6] = &arr;

   printf("%d\n", (&arr + 1) - &arr);
   printf("%d\n", (char *)(&arr + 1) - (char *)&arr);
   printf("%d\n", (unsigned)(arr + 1) - (unsigned)arr);
   printf("%d\n", (unsigned)(p + 1) - (unsigned)p);

   return 0;
}

Output:

1
210
42
210
2
  • 1
    The interesting one is the third value... Commented Aug 10, 2012 at 12:34
  • @JonathanLeffler I thought nobody was going to say anything about it :-)) Commented Aug 10, 2012 at 12:39

4 Answers 4

4

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.

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

Comments

2

They would print the same result if they were treated as pointers, but in the last printf you're forcing them to be treated as unsigned integers by casting. Thus, p + 1 and p are subtracted following integer arithmetic rules, as opposed to pointer arithmetic rules.

EDIT

To make things a little clearer:

  • When you subtract 2 pointers the result is the number of elements between them. In your case there's 1 element between them
  • When you cast the pointers to unsigned you're telling the compiler "these are just plain numbers, nothing to see here". So the compiler treats the addresses as numbers and just subtracts them.

Comments

0

The first takes the address of arr and add one, then subtracts the address, the result is clearly 1.

The last one though, p is a pointer to char [5][7][7], and using (*p)[x][y][z] can be though of as p[0][x][y][z]. So (p + 1) could be thought of as p[1], which is 210 (5 * 7 * 6) bytes away from p.

If you did (((unsigned) p) + 1) - ((unsigned) p) then that would be 1.

Comments

0

the distance between the adresses is 1 element or 210 bytes

The first print prints the number of elements The last - the number of bytes

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.