-2
#include <stdio.h>

int main(){
    int a[1] = {1};
    int b = 6;
    printf("%d\n", a[-1]);
    printf("%d\n", b);
    //printf("%d\n", (a-1 == &b));
    return 0;
}

I wrote the above code and found out it didn't work properly when using gcc or mingw to compile it, but when I uncommented 8th line, everything is just fine. Could anyone explain the code for me?

SolskGaer
  • 71
  • 7
  • When you don't have the 8th line, the compiler doesn't need the variable `b`, so it eliminates it. When you have the 8th line, then it needs `b`. Using the negative index is undefined behaviour — anything can happen when you use it. – Jonathan Leffler Sep 11 '19 at 03:54
  • 1
    b's address isn't even guaranteed to be right before a. [Why does gcc reorder the local variable in function?](https://stackoverflow.com/q/36298567/995714), [Order of local variable allocation on the stack](https://stackoverflow.com/q/1102049/995714), [Is the order of memory addresses of successively declared variables always descending?](https://stackoverflow.com/q/12438216/995714), [What is the order of local variables on the stack?](https://stackoverflow.com/q/51867757/995714), [Are C stack variables stored in reverse?](https://stackoverflow.com/q/28559007/995714) – phuclv Sep 11 '19 at 07:09
  • 1
    [Can a C compiler rearrange stack variables?](https://stackoverflow.com/q/238441/995714) – phuclv Sep 11 '19 at 07:09

3 Answers3

2

The a[-1] is undefined memory space.

daShier
  • 2,056
  • 2
  • 8
  • 14
  • In my opinion, stack grows to low address, I declare b after a, so b suppose to underneath a in memory, so I can access b using a[-1], and if I uncommented line 8, everything works just as I expected – SolskGaer Sep 11 '19 at 03:48
  • 3
    @SolskGaer — there are no guarantees about the layout of the variables. One compiler might do as you expect; others can do things differently. You're attempting to exploit undefined behaviour; any result is valid. – Jonathan Leffler Sep 11 '19 at 04:00
  • @SolskGaer You can't reason about stack frame layout without a certain system in mind. In addition, if your code does questionable things beyond the scope of the C standard, the compiler might generate wrong code, regardless of memory layout. – Lundin Sep 11 '19 at 06:59
0

Invalid Index for an array, I think you meant print a[1] printf("%d\n", a[-1])

DanielAaron
  • 101
  • 8
  • Thanks for your reply, I want to access b using a[-1] – SolskGaer Sep 11 '19 at 03:45
  • @SolskGaer `b` and `a` might not be neighbors in memory, hence accessing `b` is wrong. – Agrudge Amicus Sep 11 '19 at 03:47
  • `#include int main(){ int a[1] = {1}; int *b; b = a-1; printf("Adress of a, aka a[0]: %d\n", a); printf("Address of a-1: %d\n", a-1); printf("Address of b: %d\n",b); printf("Value b is pointing to: %d\n", *b); printf("Does the address of a== adress of b? %d\n", (a-1 == b)); return 0; }` – DanielAaron Sep 11 '19 at 03:51
  • @AgrudgeAmicus The code worked as I expected when I uncommented line 8, can you explain that for me? Thanks – SolskGaer Sep 11 '19 at 03:52
  • Sure what were you expecting – DanielAaron Sep 11 '19 at 03:53
  • @DanielAaron printf("%d\n", a[-1]) prints 6 – SolskGaer Sep 11 '19 at 03:56
  • Little confused. `printf("%d\n", a[-1]);` Prints 55 for me, depends what is in address of a[-1] `printf("%d\n", b);` Prints 6 for me since it is assigned 6 `printf("%d\n", (a-1 == &b));` Prints 0 for me since 6 != address of a - 1 If you are using codeblocks be careful, it seems to not reset the memory at that location between builds which is quite annoying. – DanielAaron Sep 11 '19 at 04:02
  • @SolskGaer Check what https://stackoverflow.com/users/15168/jonathan-leffler has commented – Agrudge Amicus Sep 11 '19 at 04:12
  • https://stackoverflow.com/questions/1677415/does-stack-grow-upward-or-downward a very detailed explanation – DanielAaron Sep 11 '19 at 04:22
0

a[-1] and a-1 result in undefined behavior. First, lets get a definition for array subscripting from the C11 standard section 6.5.2.1p2:

A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))) .

So array subscripting follows the rules of pointer arithmetic when adding an integer to a pointer.

In defining pointer arithmetic in section 6.5.6p8, it sets some rules and behavior in place (emphasis mine):

If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.

The result of the pointer arithmetic involved in the array subscripting in your question is outside of the array object, therefore it results in undefined behavior.

Christian Gibbons
  • 4,272
  • 1
  • 16
  • 29