We always have to respect the "types" though C does not always enforce it. But internally it uses the type a lot-- especially when it comes to pointers. Those who thinks in terms of types can find pointers really easy.
int *ptr=(int *)(&a+1);
Here, a is an int array. a+1 points to the second element of the array. As pointer addition says, this is numerically a + sizeof(*a) - whatever be the type of 'a'. Now, when we do &a, it returns the address of a, and the type changes to pointer to an int array of size 5. So, now, when we do b + 1, (assume b = &a), it becomes b + sizeof(*b) = &a + sizeof(5 *int). So, this just goes to the next element outside the array.
Now after addition also we get value whose type is pointer to an int array of 5 elements. And we are assigning it to a pointer to int. So, this requires a typecast. Otherwise do
int (*p)[5] = &a+1;
Now, in the printf, *(a+1) is used. Prints the second element of array - 2. *(ptr-1) - prints the last element which is 5.