411 REFERENCE · Wikibooks
A Little C Primer/Common Programming Problems in C
Reference material by Wikibooks contributors. This retains its source identity and is not 411 news reporting.
There are a number of common programming pitfalls in C that trap even
experienced programmers:
1: Confusing "=" (assignment operator) with "==" (equality operator). For
example:
if ( x = 1 ){ /* wrong! */
}
...
if ( x == 1 ){ /* good. */
}
and
for ( x == 1; ... /* wrong! */
...
for ( x = 1; ... /* good. */
2: Confusing precedence of operations in expressions. When in doubt, use
parentheses to enforce precedence.
It never hurts to use a few extra parenthesis.
3: Confusing structure-member operators. If "struct_val" is a structure and
"struct_ptr" is a pointer to a structure, then:
struct_val->myname—is wrong and so is:
struct_ptr.myname
4: Using incorrect formatting codes for "printf()" and "scanf()". Using a
"%f" to print an "int", for example, can lead to bizarre output.
5: Remember that the actual base index of an array is 0, and the final index
is 1 less than the declared size. For example:
int data[20];
...
for ( x = 1; x <= 20; ++x )
{
printf( "%d\n", data[x] );
}—will give invalid results when "x" is 20. Since C does not do bounds
checking, this one might be hard to catch.
6: Muddling syntax for multidimensional arrays. If:
data[10][10]—is a two-dimensional array, then:
data[2][7]—will select an element in that array. However:
data[ 2, 7 ]—will give invalid results but not be flagged as an error by C.
7: Confusing strings and character constants. The following is a string:
"Y"—as opposed to the character constant:
'Y'
This can cause troubles in comparisons of strings against character
constants.
8: Forgetting that strings end in a null character ('\0'). This means that
a string will always be one character bigger than the text it stores. It can
also cause trouble if a string is being created on a character-by-character
basis, and the program doesn't tack the null character onto the end of it.
9: Failing to allocate enough memory for a string—or, if pointers are
declared, to allocate any memory for it at all.
10: Failing to check return values from library functions. Most library
functions return an error code; while it may not be desirable to check every
invocation of "printf()", be careful not to ignore error codes in critical
operations.
Of course, forgetting to store the value returned by a function when that's
the only way to get the value out of it is a bonehead move, but people do
things like that every now and then.
11: Having duplicate library-function names. The compiler will not always
catch such bugs.
12: Forgetting to specify header files for library functions.
13: Specifying variables as parameters to functions when pointers are
supposed to be specified, and the reverse. If the function returns a value
through a parameter, that means it must be specified as a pointer:
myfunc( &myvar );
The following will not do the job:
myfunc( myvar );
Remember that a function may require a pointer as a parameter even if it
doesn't return a value, though as a rule this is not a good programming
practice.
14: Getting mixed up when using nested "if" and "else" statements. The best
way to avoid problems with this is to always use brackets. Avoiding
complicated "if" constructs is also a good idea; use "switch" if there's any
choice in the matter. Using "switch" is also useful even for simple "if"
statements, since it makes it easier to expand the construct if that is
necessary.
15: Forgetting semicolons—though the compiler usually catches this—or
adding one where it isn't supposed to be—which it usually doesn't. For
example:
for( x = 1; x < 10; ++x );
{
printf( "%d\n", x );
}—prints only the number 10.
16: Forgetting "break" statements in "switch" constructs. As commented
earlier, doing so will simply cause execution to flow from one clause of the
"switch" to the next.
17: Careless mixing and misuse of signed and unsigned values, or of
different data types. This can lead to some insanely subtle bugs. One
particular problem to watch out for is declaring single character variables
as "unsigned char". Many I/O functions will expect values of "unsigned int"
and fail to properly flag EOF. It is recommended to cast function arguments
to the proper type even if it appears that type conversion will take care of
it on its own.
18: Confusion of variable names. To ensure portability of code, it is recommended that the first six characters of such identifiers be unique.
19: In general, excessively tricky and clever code. Programs are nasty
beasts and even if it works, it will have to be modified and even ported to
different languages. Maintain a clean structure and do the simple
straightforward thing, unless it imposes an unacceptable penalty.