Lately I have been editing an otherwise well-structured and intelligible program written by a C programmer who habitually iterates over linked lists using the following idiom:
int print_shopping_list( listitem_t *list, int max_price ) {
int found_count = 0;
listitem_t *item = list;
while (item != NULL) {
if ( item->price <= max_price ) {
printf( "Buy %s priced at %d pence", item->name, item->price );
found_count++;
}
item = item->next;
}
return found_count;
}
Superficially, there is nothing wrong with this. However, consider what happens if another programmer (with a nut allergy) adapts the program to reject peanuts:
int print_shopping_list( listitem_t *list, int max_price ) {
int found_count = 0;
listitem_t *item = list;
while (item != NULL) {
if ( item->type == ITEMTYPE_PEANUTS ) {
continue; /* No peanuts because of my allergy */
}
if ( item->price <= max_price ) {
printf( "Buy %s priced at %d pence", item->name, item->price );
found_count++;
}
item = item->next;
}
return found_count;
}
Oh dear! The modified program will never terminate if it
encounters peanuts in the shopping list, because
continue jumps to the next loop iteration without
assigning a new value to the current item pointer.
This error could have been averted, had the original
programmer used a for statement instead of
while:
int print_shopping_list( listitem_t *list, int max_price ) {
int found_count = 0;
for ( listitem_t *item = list;
item != NULL;
item = item->next ) {
if ( item->type == ITEMTYPE_PEANUTS ) {
continue; /* No peanuts because of my allergy */
}
if ( item->price <= max_price ) {
printf( "Buy %s priced at %d pence", item->name, item->price );
found_count++;
}
}
return found_count;
}
The above code works because the third expression of a
for statement (to advance to the next iteration) is
executed after a continue statement.
Any loop in the following form:
for( a; b; c ) {
d;
}
can be rewritten as multiple statements:
a;
while( b ) {
d;
c;
}
Most modern programming languages offer
continue, for and while
statements. In my view the while statement
should never be used for loops that require separate
expressions to test for termination and to advance to the
next iteration.
In a while loop, the next-iteration expression
is too easily omitted or not executed if it is in a separate
statement marooned at the end of the loop's body (which may
be many lines distant).
for instead of while makes
programs more concise, more robust, and easier to read because
all of the expressions relating to a loop are on the same line
(or a few consecutive lines).