What a nice book! After browsing just a few pages, it is obvious that this is the right way to teach a language. The author presents the major concepts and constructs of C in 110 short source code puzzles (1–10 per page), which the reader can solve by deciding what each will print when it executes. Here is an example:
x = 03; y = 02; z = 01; PRINT (x | y & z);
(Answer: 3, since & has higher precedence than |. PRINT is one of several preprocessor macros used in the text.) If you understand the concepts, you can correctly predict the output.
The book is intended to be used as a workbook, along with any standard text on the C language. However, experienced programmers might prefer to use the puzzles instead of a text, consulting a standard reference only for specific questions. (After all, most of us learned our last five languages by experimenting at the keyboard; puzzles are the printed equivalent. Educators take note!)
The book contains three main sections--puzzles, solutions, and appendices. Each right-hand puzzle page is a set of related source code fragments. The answers follow on the back (that is, on the next left-hand page), showing the actual printed output. In the few cases with machine-dependent results (for example, due to processor word length), both Sun-3 (UNIX) and PC/AT (MS-DOS) output are included. In addition, the author presents clear, annotated solutions in a separate section, taking up roughly half the book. The solutions are the real meat of the book, and the points illustrated by the puzzles are clarified and hammered home. Finally, four appendices summarize operator precedence, operator semantics, the ASCII character set, and the hierarchy of C implicit type conversions.
The puzzles are grouped into eight subsections--operators, basic types, control flow, programming style, storage classes, pointers and arrays, structures, and the preprocessor. Each section implicitly focuses on one or two big points, lessons familiar to all experienced C programmers. Some of the important issues include the use of parentheses when there is any doubt about evaluation order, the avoidance of side effects, especially in preprocessor macros, which cause strange results, the avoidance of mixed-typed computations by cautiously using explicit type casts, and the importance of clear indentation and appropriate structural choices. Such lessons cannot really be learned by rote; the “Aha!” experience is necessary, and these puzzles are an effective substitute for an office-mate interjecting a timely “Oh, I see your problem ….”
Accolades aside, there are two things wrong with this book. The first is that a few solutions are missing or appear in the wrong order. Given the otherwise careful attention to detail, this is surprising, especially for a second edition. The second problem is that too much space is devoted to proving that humans forget precedence rules and get confused by complex syntax. These are not hard points to make. Perhaps some programmers need to have it drilled in that they should use parentheses, make the meaning obvious, and avoid hacks, but it simply is not fun struggling through messy expressions that would get any professional who wrote them fired on the spot.
In other words, learning C is more than just learning syntax. Style deserves more than just two puzzle pages, and style is more than just using good judgment in picking constructs. C involves a different approach to many problems. The book would be better if the human compiler parts were replaced with sections helping new C programmers learn C-style (rather than FORTRAN-style or COBOL-style) strategies. Useful topics for the third edition might include using character- and pointer-driven processing instead of fixed-format record structures, managing heap storage, optimizing inner loops, designing effective structures, managing linked lists of various kinds, converting loops into recursive functions, and locating storage leaks and pointer bugs (the most pervasive C errors?). True, these are more advanced topics, but it is in areas like these (and not in memorizing the precedence of bit-shift operators) that C’s special advantages and peculiarities are most visible and important.
However, these complaints are minor; the book is good. Any newcomer to C needs it. Casual users with an incomplete knowledge of C will benefit from it. Educators and writers of training material will definitely benefit from it.