General Observations
There are problems using the first version of the book,: the C programming language changed a great deal when it switched to ANSI in 1989, prefer. Prefer the second version if you can get it,it; there are also more modern books written by other authors.
Some of the differences are how parameters are declared in functions. Then there is the fact that the ANSI standard allowed variablevariables to be declared anywhere while the original requirerequires variable declarations to be at the top of the functiontheir containing block.
Calling exit(status) From Main
The default behavior of int main() is to return the status of the program to the operating system,system; there is no need to ever call exit() from main. The exit() function is there so that the C program can exit from other functions besides main in case of error situations.
Prefer Functions Over Macros
The macro calc_n_spaces() would be better as either a function or inline code. The current implementation doesn't save either programming space (lines of code) or performance. Modern optimizing compilers might very turn a function into inline code.
Code Organization
Function prototypes are very useful in large programs that contain multiple source files, and that in case they will be in header files. In a single file program like this it is better to put the main()main() function at the bottom of the file and all the functions that get used in the proper order above main()main(). Keep in mind that every line of code written is another line of code where a bug can crawl into the code.