To explain how negative indexes work, you first have to learn (or remember) that for any array or pointer a and index i, the expression a[i] is equal to *(a + i).
That means that you can have a pointer to the middle element of an array, and use it with a positive or negative index, and it's simple arithmetic.
Example:
int a[3] = { 1, 2, 3 };
int* p = &a[1];  // Make p point to the second element
std::cout << p[-1];  // Prints the first element of a, equal to *(p - 1)
std::cout << p[ 0];  // Prints the second element of a, equal to *p
std::cout << p[ 1];  // Prints the third element of a, equal to *(p + 1)
Somewhat graphically it can be seen like
+------+------+------+
| a[0] | a[1] | a[2] |
+------+------+------+
^      ^      ^
|      |      |
p-1    p      p+1
Now when using a negative index in an array, as in the example of a in the question, it will be something like this:
+-----+-------+-------+------+------+------+
| ... | a[-2] | a[-1] | a[0] | a[1] | a[2] |
+-----+-------+-------+------+------+------+
That is, negative indexes here will be out of bounds of the array, and will lead to undefined behavior.