24

I came along a competitive question that asks the output of the following:

#include <stdio.h>
int main()
{
    int a[] = {0,1,2,3,4};
    int i, *ptr;
    for(ptr = a+4, i=0; i <=4; i++)
    printf("%d", ptr[-i]);
    return 0;
}

I did read this topic: Are negative array indexes allowed in C? However it was unclear to me how the -ve symbol generates the array in the reverse order, ie. 4, 3, 2, 1, 0.

Community
  • 1
  • 1
Jishan
  • 1,654
  • 4
  • 28
  • 62
  • 9
    Per the title of your question, you're not using a negative number as an *array* index; You're using a pointer `ptr` and index `-i`to calculate *pointer arithmetic* to some element within `a[]`. The array `a[]` is always rooted at `0` and dereferencing into *it* via `a[n]` for some `n` less than zero is undefined behavior. Arrays aren't pointers. The tidal wave of answers below explain the pointer math concept well. – WhozCraig Aug 29 '14 at 18:49
  • 2
    `a[b]` == `*(a + b)` == `b[a]` – frogatto Aug 30 '14 at 12:51
  • Remeber WhozCraig's answer from above. During your career you may com across code where such pointers are used to "poke" and "zap" values in arrays of "bytes". This is sometimes even used to hammer in a null to terminate strings ? The above question waxes "pythonesque" as negatives can be used in Python ? – mckenzm Dec 02 '14 at 19:17

6 Answers6

26

First, recall that in C the expression ptr[index] means the same thing as *(ptr+index).

Now let's look at your expression again: ptr is set to a+4 before the loop; then you apply -i index to it. Therefore, the equivalent pointer arithmetic expression would be as follows:

printf("%d", *(a+4-i));

This expression iterates the array backwards, producing the results that you see.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
4

The reason it works is because the [] operator does pointer addition.

When you reference

a[x]

Whats actually happening is its taking the memory address of a and adding the sizeof(int)*x

So if you set ptr to a+4, you are going to a+sizeof(int)*4

then, when you put in a negative value, you move backwards through the memory address.

QuinnFTW
  • 554
  • 5
  • 12
3

a+4 gives a pointer to the fifth element of a. So ptr refers to that location.

Then the loop counts i from 0 up to (and including) 4.

The dereference ptr[-i] is equivalent to *(ptr - i) (by definition). So, since i is 0 and ptr is a+4, it's equivalent to a+4-0, then a+4-1, then a+4-2, and so on until a+4-4, which is (obviously enough) equal to a.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
3

ptr[-i] decays into *(ptr + (-i)). At the first iteration, when i = 0, ptr[-i] accesses last element of a array, because initially ptr was set to be equal a + 4, which means - take address of beginning of a and add 4 * sizeof(int) (because ptr was of size int). On every next iteration, when i is incremented, previous element of array is accessed.

macfij
  • 3,093
  • 1
  • 19
  • 24
  • Strictly spoken, expression one doesn't "decay" into expression two: they simply are equivalent expressions. If you'd write `*(a + (-i))` though with the OP's definition of a as an array, a would indeed decay to a pointer to a's first element. – Peter - Reinstate Monica Aug 30 '14 at 14:28
3

In is for statement

for(ptr = a+4, i=0; i <=4; i++)

pointer ptr is set to a+4 It could be done also the following way

ptr = &a[4];

If you tray to output the value pointed to by the pointer as for example

printf( "%d\n", *ptr );

you will get 4. That is the pointer points to the last element of the array.

Inside the loop there is used expression ptr[-i] . for i equal to 0 it is equivalent to ptr[0] or simply to *ptr that is the last element of the array will be outputed. For i equal to 1 expression ptr[-i] is equivalent to a[4 - 1] or simply a[3]. When iequal to 2 when expression ptr[-i] is equivalent to a[4 - i] that is a[4 - 2] that in turn is a[2] and so on. SO you will get

4321
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2

As I mentioned in my comment in C/C++

a[b] == *(a+b) == b[a]

For your case all of these is fine

printf("%d", *(a + 4 - i));
printf("%d", a[4 - i]);
printf("%d", 4[a - i]);
...
frogatto
  • 28,539
  • 11
  • 83
  • 129