This type of code used to run faster when compilers did less. It makes no difference now. I think that is why it has stuck around. I prefer to write C that uses array references where it makes things clearer.
Don't think so. Kernighan et al. are the first to say code should be clear first and made fast only if it matters. This is clear code. It may (or may not) be faster than an array-based version but that's not the point of the exercise in K&R -- the point is to teach how pointers work.
You'd be surprised what the compiler still doesn't do. For example, when writing a toy high-performance memory allocator for a university class, I was able to gain a significant[1] performance boost by replacing __attribute__((packed)) structs with pointer arithmetic #defines for the allocation block descriptors, with an identical memory layout.
[1] I don't remember the exact gain, but it was at least 10%.