How does incrementing memory address affects pointer

Viewed 95

I am seeking for an explanation regarding how incrementing an address affects a pointer.

I learned about how C pointers work and how incrementing a pointer is done by considering the pointer type. still I don't understand the following case

int main()
{
    int a[] = {1,2,3,4,5};
    int *p = (int*)(&a+1);
    printf("%d\n%d\n", *(a+1), *(p-1));
    return 0;
}

I expected this line

int *p = (int*)(&a+1);

to make p point to the address that follows array a, therefore I expected the output:

2 

as it is simply a[1]

But the output was unknown_number - as I don't know which int is 4 bytes behind (&a+1)

And the actual result is:

2

5

Why does it seems that p points directly to the memory sitting after a?

What is the source for my confusion?

3 Answers

So in this example &a is of type int(*)[5]. When you add 1 to it it actually adds sizeof(int[5]) - because that is how pointer arithmetic works, adding an offset adds the size of the type being pointed to times the offset. That is how you get p to be one past last element of a, after which you cast it to int* so now you have a pointer pointing to an integer at an address one past the last element of a. So effectively, subtracting 1 from it gives you the last element of a.

Two basic concepts:

  • Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, a expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.

  • Adding 1 to an expression of type "pointer to T" yields the address of the object of type T immediately following the current object. IOW, if p points to a 4-byte int, p+1 points to the int immediately following it. If p points to a 5-element array of int, then p+1 points to the next 5-element array of int immediately following it. This is how array indexing works - the subscript operation a[i] is defined as *(a + i). Given a starting address a (either a pointer expression or an array expression that decays to a pointer), find the address of the i’th object following that address and dereference the result.

So, if you have the declaration

int a[] = {1, 2, 3, 4, 5};

then the following are true:

  • the expression a has type "5-element array of int" (int [5]) - if the expression is not the operand of the sizeof or unary & operators, it "decays" to type "pointer to int" (int *) and its value is the address of the first element of the array (&a[0]).

  • the expression *(a + 1) is identical to a[1], and evaluates to the second object in the array (2).

  • the expression &a + 1 has type int (*)[5] and yields the starting address of the 5-element array of int after a. The type of this expression is converted to int * and assigned to p.

  • the expression p has type int * - subtracting 1 from this yields the address of the int object immediately preceding p, which happens to be the last element of a.

Graphically:

   +–––+
a: | 1 |
   +–––+
   | 2 | <–– a + 1
   +–––+
   | 3 |
   +–––+
   | 4 |
   +–––+
   | 5 | <–– p - 1
   +–––+
   | ? | <–– p (&a + 1)
   +–––+

You can manipulate the array a as a pointer to a int int *. But it is not the same for &a, which is a pointer to an array of 5 ints : &a + 1 will add the size of the 5 ints to the pointer.

Just remove the & before adding 1 to a, and it'll work as you expected:

#include <stdio.h>

int main()
{
    int a[] = {1,2,3,4,5};
    int *p = (int*)(a+1); // & removed
    printf("%d %d\n", *(a+1), *(p-1));
    return 0;
}
Related