i'd like to add that the multidimensional arrays are stored contiguously in memory. statement
int aMatrix[5][5];
is evaluated by compiler to
int (*aMatrix)[5];
so it is a pointer to 5 element array of ints. that's the size of your column. C doesn't check for boundaries and compiler doesn't know that there are 5 rows in your matrix.
furthermore, statement
aPtr = &aMatrix[1][1];
is evaluated to
aPtr = &(*(*(aMatrix + 1) + 1));
so it takes the address of aMatrix, by adding 1 it really adds 5, because aMatrix points to 5 ints. then, it is dereferenced and now just 1 is added. then, another dereference and aPtr points to address of that cell.
aPtr points to one int. so aPtr[2] adds 2. to sum up, 5+1+2 = 8.
what aMatrix really look like is
aMatrix ---> [0 1 2 3 4] [5 6 7 8 9] [10 11 12 13 14] [15 16 17 18 19] [20 21 22 23 24]
^ |______________|
aMatrix[0][0] aMatrix[2]
you could get the same output by, for instance, writing following code:
int* testPtr = &aMatrix[0][0];
printf("%d\n",testPtr[8]);