K&R knew C had a great weakness in program flow control, and incuded goto for the very good reason of allowing a powerful performance improving option. It's a shame students today are not taught to be as smart as K&R.
My physical first-edition copy of K&R reads (paperback, pages 62-63):
"C provides the infinitely-abusable goto statement, and labels to branch to. Formally, the goto is never necessary, and in practice it is almost always easy to write code without it. We have not used goto in this book."
The text then goes on to discuss and show the "deeply nested structure" usage of goto (for arguable "error handling"); it also shows a method to break out of a double nested loop while searching for a negative element in a 2-dimensional array, but then states:
"Code involving a goto can always be written without one, though perhaps at the price of some repeated tests or an extra variable."
It then shows the same negative-element-finding code re-written without the goto. The text ends with:
"Although we are not dogmatic about the matter, it does seem that goto statements should be used sparingly, if at all."
---
I'm not sure the usage within a state-machine context could be considered "sparingly"; maybe for simple state machine definitions. It is likely that today's modern compilers can do a far better optimization of the code whether you use it or not. Many of today's micro-controllers (not all, though) have more capabilities, RAM, ROM, program memory, etc - than some of the mini-computers which were around when K&R were writing the language.
I'm not saying that for micro-controllers a programmer shouldn't have performance in mind, but it should be a careful balance, especially if it is possible (read: likely/always) that the code might be reused or re-visited in the (near/far) future for maintenance. If the balance is met, the code should end up with good performance and good maintainability. Edge cases should be dealt with on an as-needed basis, of course...