-1

My code:

#include<stdio.h>
#include<stdlib.h>

int main()
{
    int *pi;
    short *ps;

    pi = malloc(16 * sizeof *pi);
    ps = malloc(16 * sizeof *ps);
    pi += 8;
    ps += 8;
    ps = (short*) pi;
    *pi = 1000000;
    printf("*pi = %d,", *pi);
    printf("*ps = %hd\n", *ps);
    printf("before incrementing ps : ps = %p\n", ps);
    ps++;
    printf("after incrementing ps : ps = %p\n", ps);
    printf("*ps = %hd\n", *ps);
    *ps = 16;
    printf("after *ps = %hd -> *pi = %d\n", *ps, *pi);
    printf("ps - 1 = %p, -1 + ps = %p\n", ps - 1,-1 + ps);
    printf("*(ps - 1) = %hd, *(-1 + ps) = %hd\n", *(ps - 1), *(-1 + ps));
    printf("0[ps - 1] = %hd, 1[ps - 2] = %hd, ps[-1] = %hd\n", 0[ps - 1], 1[ps - 2], ps[-1]);
    printf("-1[ps] = %hd, -2[ps + 1] = %hd, -3[ps + 2] = %hd\n", -1[ps], -2[ps + 1], -3[ps + 2]);
    printf("-3[ps] = %hd, -3[ps + 1] = %hd, -3[ps + 3] = %hd,", -3[ps], -3[ps + 1], -3[ps + 3]);
    printf("-3[ps + 4] = %hd\n",-3[ps + 4]);
}
/* format string in printf was adjusted to increase readability */

My output:

*pi=1000000,*ps=16960
before incrementing ps:ps=0xbb9030
after incrementing ps:ps=0xbb9032
*ps=15
after *ps=16->*pi=1065536
ps-1=0xbb9030,-1+ps=0xbb9030
*(ps-1)=16960,*(-1+ps)=16960
0[ps-1]=16960,1[ps-2]=16960,ps[-1]=16960
-1[ps]=0,-2[ps+1]=0,-3[ps+2]=0
-3[ps]=0,-3[ps+1]=0,-3[ps+3]=0,-3[ps+4]=0

I have read that a[b] is defined as *(a+b). Therefore, ps[-1]==*(ps-1)==*(-1+ps)==-1[ps]. But, as seen in the output, while it is the case that all expressions except the last have the expected value (of 16960), the last one has the value 0?

Why does this happen? Does -x[ps] produce undefined behavior, causing the compiler to just use 0?

For your information, I use gcc. gcc -v outputs gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.5).

user351579
  • 129
  • 6
  • 1
    Youknowthatthecompilerignoreswhitespaces,don'tyou? This code is too unreadable and too boring to read, please explain your precise problem and try to reproduce it in a simpler program. Also, do you know that `1[x] is the same as x[1]`? – Iharob Al Asimi Oct 12 '17 at 15:08
  • I have no idea what you are talking about or what this code is supposed to achieve. – Eugene Sh. Oct 12 '17 at 15:08
  • 1
    @EugeneSh. This is a piece of code to experiment with pointer arithmetic. – user351579 Oct 12 '17 at 15:09
  • This experiment seems to me more about the syntax you can use to perform pointer arithmetics, which is an interesting topic, but you should try to stick to a given syntax, like `x[n]` which is the more readable and intuitive. – Iharob Al Asimi Oct 12 '17 at 15:10
  • Then isolate the piece of code which is puzzling you and explain the expected and actual behavior. – Eugene Sh. Oct 12 '17 at 15:11
  • `ps[-1]` is the same as `(-1)[ps]`, but `-1[ps]` is `-(1[ps])`, i.e. `-ps[1]`. You forgot the parentheses. – Tom Karzes Oct 12 '17 at 15:11
  • @IharobAlAsimi Fixed – user351579 Oct 12 '17 at 15:16

1 Answers1

4

Unary negation - has a lower precedence than [].

So -1[ps] is evaluated as -(1[ps]).

You should also note that pointer arithmetic is only defined within arrays: with the important exceptions that you are allowed to set (though not dereference) a pointer one past the end of an array, or one past the address of a scalar.

Everything else is pretty obvious: particularly you can't access outside the bounds of an array.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • Also, asserting that `-x[ptr]` is always `0` is wrong. Because a simple test could demonstrate that it's not true. – Iharob Al Asimi Oct 12 '17 at 15:12
  • @IharobAlAsimi Are you saying that the expressions on the bottom row of the output is zero simply because malloc allocated a piece of memory that was zero? It's very unlikely, as I have run the code multiple times. You can see that even 3[ps + 4] is in the bounds of the array. – user351579 Oct 12 '17 at 15:23
  • @IharobAlAsimi Well, I did some more experimenting and found that the array *was*, mysteriously, filled by 0s. – user351579 Oct 12 '17 at 15:34
  • @user_194421: `malloc` doesn't have to do that. `calloc`, on the other hand, does. See https://stackoverflow.com/questions/1538420/difference-between-malloc-and-calloc – Bathsheba Oct 12 '17 at 15:34
  • @Bathsheba But as you can see I used malloc, and I added a piece of code to print the entire malloced memory. It was filled by 0, except the places which I assigned a nonzero value. – user351579 Oct 12 '17 at 15:35
  • @user_194421: Indeed, but this isn't *standard*. On another platform, or even on yours on a different occasion, the memory buffer might not be zero initialised. – Bathsheba Oct 12 '17 at 15:36
  • @Bathsheba I have run the code like *dozens* of times, and it was zeroed. I therefore can conclude that gcc, at least the version I use, zeroes the memory it mallocs. Or can I? – user351579 Oct 12 '17 at 15:39
  • No you can conclude no such thing. Although it can be sometimes frustratingly difficult to get malloc to give you a non-zeroed buffer. Why not search around the internet for some examples? – Bathsheba Oct 12 '17 at 15:41
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/156575/discussion-between-user-194421-and-bathsheba). – user351579 Oct 12 '17 at 15:41