Thoughts on the Craft of Programming: Abstraction, Refactoring, and How Changes Introduce Bugs - Bugs
(Page 2 of 6 )
Fixing a Bug The first code sample (Figure 1) comes from one of the advertisements that Gimpel Software runs every month in Dr. Dobb's Journal; each advertisement illustrates a bug that could be found by their enhanced version of the source code diagnostic program lint2 and that therefore can be discovered by visual inspection of the code. The failure, as stated in the ad, is "This function which is intended to count the vowels in the string provided is taking a long time to do so." I found that under either Windows or Linux the actual failure is that an addressing exception is generated.
Figure 1: Incorrect Code from Gimpel Ad The error results from the coder's failure to see and appreciate the implication of C syntax: the break statement is in the scope of the switch statement, not that of the for statement, and consequently causes exit from the switch but not from the for. One is misled by the two continue statements, which are indeed in the scope of the for loop. So the for statement in fact has no termination condition, and thus after a potentially long series of character accesses, an invalid address is generated.
Making the Initial Bug Fix
An explicit infinite loop (such as the C idiom "for (;;)") should always be viewed with suspicion, for very few loops, if indeed any, are truly endless. Let's put the termination condition in the loop, which is clearer and also fixes the bug. The new for statement is another piece of C idiom (a cliché, if you will) that is instantly recognizable to an experienced C programmer as an instance of the scan-the-whole-string pattern (though some C programmers would omit the explicit comparison to the null character and rely on C's implicit comparison). Note that we no longer need the "case '\0':", since the loop condition now guarantees this case would never arise. This code is definitely more readable than the original, and an experienced programmer could comprehend the whole thing in little more than a glance.
Although Java's for and switch statements work in exactly the same way as C's and expose the programmer to the same error, a Java programmer almost certainly would not have made this mistake. That is because Java strings use a length rather than a terminating character, and a Java programmer would automatically write the loop in the Java idiom:
for (int i = 0; i < s.length(); i++)
So, by using a termination condition directly in the loop definition, we can fix the bug as shown in Figure 2:
Figure 2: Fixing the BugNext: Cleaning Code >>
More Development Cycles Articles
More By The Rational Edge