8

I just saw this code snippet Q4 here and was wondering if I understood this correctly.

#include <stdio.h>

int main(void)
{
   int a[5] = { 1, 2, 3, 4, 5 };
   int *ptr = (int*)(&a + 1);

   printf("%d %d\n", *(a + 1), *(ptr - 1));

   return 0;
}

Here's my explanation:

int a[5] = { 1, 2, 3, 4, 5 }; => a points to the first element of the array. In other words: a contains the address of the first element of the array.

int *ptr = (int*)(&a + 1); => Here &a will be a double pointer and point to the whole array. I visualize it like this: int b[1][5] = {1, 2, 3, 4, 5};, here b points to a row of a 2D array. &a + 1 should point to the next array of integers in the memory (non-existent) [kind of like, b + 1 points to the second (non-existent) row of a 2D array with 1 row]. We cast it as int *, so this should probably point to the first element of the next array (non-existent) in memory.

*(a + 1) => This one's easy. It just points to the second element of the array.

*(ptr - 1) => This one's tricky, and my explanation is probably flawed for this one. As ptr is an int *, this should point to int previous to that pointed by ptr. ptr points to the non-existent second array in memory. So, ptr - 1 should probably point to the last element of the first array (a[4]).

Aneesh Dogra
  • 740
  • 5
  • 30
  • 3
    where is the question? you proposed a code and you have well explained – MOHAMED Jan 03 '14 at 07:15
  • 1
    what ever you have understood is absolutely fine and correct:) – Amit Jan 03 '14 at 07:16
  • `&a` is a "`double[5]`" pointer (in your speak), not a `double` pointer; hence the need for the cast. – CB Bailey Jan 03 '14 at 07:18
  • @AneeshDogra: It will not be a double (two star) pointer but it's specific type is `int (*) [5]`. You're typecasting it into an `int*`. – legends2k Jan 03 '14 at 07:26
  • @legends2k What's the difference between int (*) [5] and int **? – Aneesh Dogra Jan 03 '14 at 07:32
  • you are asking Question or Answer here ?? – Subhalaxmi Jan 03 '14 at 07:32
  • @subhalaxminayak Quoting from the post: `was wondering if I understood this correctly.` – Aneesh Dogra Jan 03 '14 at 07:33
  • i want to upvote but there is no question here – user3125280 Jan 03 '14 at 07:33
  • @user3125280 I wanted to check my explanation about the code. I think my explanation is flawed and want someone to correct me. – Aneesh Dogra Jan 03 '14 at 07:34
  • 2
    @AneeshDogra: `int(*)[5]` is of type _pointer to an array of 5 integers_, while `int**` is a _pointer to a pointer to an integer_. The former decays into latter in some scenarios, NOT all. – legends2k Jan 03 '14 at 07:39
  • @legends2k Thanks. That helps. Could you point me to some reading material to read about some of those scenarios. – Aneesh Dogra Jan 03 '14 at 07:40
  • @AneeshDogra: [How do I use arrays in C++?](http://stackoverflow.com/questions/4810664/how-do-i-use-arrays-in-c) should help, although it's for C++, it's relevant in C too for the most part. – legends2k Jan 03 '14 at 07:45
  • @AneeshDogra the site you got that from contains the question, answer and explanation, as well as many similar scenarios. Almost tempted to downvote actually, but i did at least learn something – user3125280 Jan 03 '14 at 07:51
  • @legends2k: When does a pointer to one type ever decay to a pointer to a different type? I cannot think of any such case off hand. – CB Bailey Jan 03 '14 at 20:50
  • Aah, you're right, never does it decay! Only an array type decays, hasty comment, poor wording :( – legends2k Jan 03 '14 at 23:12

3 Answers3

6
Here &a will be a double pointer.

No. It is a pointer to an array. In this example, int (*)[5]. Refer C pointer to array/array of pointers disambiguation

so when you increment pointer to an array, it will crosses the array and points to non-existent place.

In this example, It is assigned to integer pointer. so when int pointer is decremented, it will point to previous sizeof(int) bytes. so 5 is printed.

Community
  • 1
  • 1
Jeyaram
  • 9,158
  • 7
  • 41
  • 63
1

As per your explanation you understand array pointer correctly.Using statement

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

you point to the next address of address occupied by whole array a[] so you can access the array element using ptr by decrementing address of ptr.

Jayesh Bhoi
  • 24,694
  • 15
  • 58
  • 73
1

Your statement is essentially correct, and you probably understand it better than most professionals. But since you are seeking a critique, here is the long answer. Arrays and pointers in C are different types, this is one of the most subtle details in C. I remember one of my favorite professors saying once that the people who made the language latter regretted making this so subtle and often confusing.

It is true in many cases an array of a type, and a pointer to a type can be treated the same way. They both have a value equal to their address, but they are truly different types.

When you take the address of an array &a, you have a pointer to an array. When you say (a + 1) you have a pointer to an int, when you just say a you have an array (not a pointer). a[1] is exactly the same as typing *(a + 1), in fact you could type 1[a] and it would be exactly the same as the previous two. When you pass an array to a function, you are not really passing an array, you are passing a pointer void Fn(int b[]) and void Fn(int *b) are both the exact same function signature, if you take sizeof b within the function, in both cases you will get the size of a pointer.

Pointer arithmetic is tricky, it always offsets by the size of the object it's pointing to in bytes. Whenever you use the address of operator you get a pointer to the type you applied it to.

So for what's going on in your example above:

  • &a is a pointer to an array, and so when you add one to it, it is offset by the sizeof that array (5 * sizeof(int)).
  • When you cast to int*, the cast retains the value of the pointer, but now its type is pointer to int, you then store it in ptr, a variable of type pointer to int.
  • a is an array, not a pointer. So when you say a + 1 you apply the addition operator to an array, not a pointer; and this yields a pointer to one-past the first element of the type stored in the array, int. Dereferencing it with * gives you the int pointed to.
  • ptr is a pointer to int, and it points one past the end of the array. (it is legal by the way to point one past the end of an array, it's just not legal to dereference this pointer) When you subtract 1 from it, you end up with a pointer to an int that is the last in the array, which you can dereference. (Your explain of visualizing int b[1][5] = {1, 2, 3, 4, 5}; is something I've not heard before, and while I can't honestly say if this is technically correct, I will say this is how it works and I think this is a great way to think of it; I will likely do so in the back of my mind from now on.)

Types will get very tricky in C, and also in C++. The best is yet to come.

Apriori
  • 2,308
  • 15
  • 16