Previous | Table of Contents | Next |
Although C has plenty of built-in traps, Cs design is probably less to blame for pointer problems than C programmers fascination with clever coding. Consider the cat function in Figure 6.14. This function places the concatenation of two null-terminated strings (passed as parameters str1 and str2) in the result string. I wrote cat using a typical C idiom. The beauty of this style lies in how much work gets done in the two short while expressions. Each execution of
while(*result++ = *str1++)
works like this:
Figure 6.14 cat Function
void cat fees( char * result, const char * str1, const char * str2 ) { /* Concatenate str1 and str2 and return in result */ while(*result++ = *str1++); result while(*result++ = *str2++); }
When the first while loop is completed, result contains the address one beyond the terminating null of the target string. The result statement shifts this address back one, so the second while loop repeats the process just described, starting at the byte just after the last non-null character in the target.
If youre an inexperienced C programmer, this code probably looks odd to you. You may not even be sure it works reliably. But if you aspire to be a competent C programmer, much of the advice youll receive will try to help you master Cs concentrated syntax so that you will know how this code works and that it does do what I said. Unfortunately, too many C programmers concentrate so much on coding details (such as when the post-increment operator takes effect and the relative precedence of the * and ++ operators) that they deliver tight while loops but miss larger problems. Such misplaced attention can lead to functions such as cat that are fast, but explosive.
Figure 6.15a shows a sample call to cat that prints Hello world! just what youd expect. Figure 6.15b shows another call to cat that freezes your PC and requires a reboot. Since the second example passes string b as both the target string (result parameter) and the second source string (str2 parameter), the second while loop in cat chases b to infinity. On every iteration, we advance the pointer one more byte toward the end of str2 (which is b), but by adding a byte to the tail of result (which is also b), we make the end of str2 just one byte farther away.
Figure 6.15a A Successful Call of cat
char a[20] = "Hello "; char b[20] = "world!"; char x[20]; cat(x, a, b); printf("%s\n", x); /* Prints: Hello world! */
Figure 6.15b An Unsuccessful Call of cat
char a[20] = "Hello "; char b[20] = "world!"; char x[20]; cat(b, a, b); /* Infinite loop! */ printf("%s\n", b);
Similar problems can occur in RPG, COBOL, and any other language that passes addresses for procedure arguments. But because RPG and COBOL programmers dont have to concentrate so much on low-level coding details (or maybe because RPG and COBOL programmers dont so readily dare to boldly go where no one has gone before), they dont seem to write as much self-destructing code as C programmers.
That brings me to my last suggestion in this chapter for avoiding Cs pitfalls: avoid popular, but tricky, C idioms for business application programming. Instead, use code that is readily understood and easily checked for validity.
Previous | Table of Contents | Next |