In your output, arr is at the location 0x7ffe3c5fc3a4
Since we have an array of integers, so
std::cout << sizeof(int);
gives an output of 4 i.e. each int in our array will take up 4 bytes (Whether an int will take up 2 bytes or 4 bytes or something else will depend upon the implementation being used. That is why I used sizeof to find out the size being used for int by this specific implementation).
Let us move back and find the location of the first element of the array arr
If we subtract (9 times 4) = 36 bytes [36 in decimal is 0x24 in hex], then we will find the location of arr
0x7ffe3c5fc3a4 - 0x24 = 0x7ffe3c5fc380
So, arr is at location 0x7ffe3c5fc380
If we go back 4 bytes i.e. arr[-1], we get
0x7ffe3c5fc380 - 0x4 = 0x7ffe3c5fc37c
which is the other output mentioned in your post.
Use of negative index varies by language.
In Python/Ruby, we can use arr[-1] to find the last element.
In Java, negative index will give error.
In C/C++, negative index will not give us the last element. Instead arr[-1] in the above snippet posted by you will take us 4 bytes (the size of one element) back from arr. We will go out of bounds of the array, but in C/C++ the responsibility is on the programmer to respect the bounds (In other languages such as Python, an index error will be thrown). In C/C++, we get undefined behavior. If you print out the value stored in arr[-1], you will most likely see some random number or an error or something else (hence the term undefined behavior).