C Programming For Dummies
Book image
Explore Book Buy On Amazon
The programming adventure has its pitfalls and most C programmers can’t claim to be free of some mistakes. Many of them are common; the same mistakes, over and over. Even after decades of coding, C programmers often still find themselves doing stupid, silly things. Most often they’re done in haste — usually, simple things. But isn’t that the way of everything?

C programming mistakes © Shutterstock/GaudiLab

Conditional Foul-Ups

When you employ an if statement or initiate a while or for loop, the code makes a comparison. Properly expressing this comparison is an art form, especially when you try to do multiple things at once.

My advice is to first split up the code before you load everything into the parentheses. For example:

while((c=fgetc(dumpme)) != EOF)
The code on the preceding line works, but before you get there, try this:
c = 1;            /* initialize c */
while(c != EOF)
    c=fgetc(dumpme);
This improvement is more readable and less error prone.

The situation grows more hair when you use logical operators to combine conditions. It’s highly recommended that you limit the expression to two choices only:

if( a==b || a==c)
The statements belonging to if are executed when the value of variable a is equal to either the value of variable b or variable c. Simple. But what about this:
if( a==b || a==c && a==d)
Oops. Now the order of precedence takes over, and for the if statement to be true, a must be equal to b, or a must be equal to both c and d. The situation can also be improved by using parentheses:
if( a==b || (a==c && a==d))

When you’re unsure about the order of precedence, use parentheses.

== v. =

A single equal sign is the assignment operator:
a=65;
A double equal sign is used for comparison:
a==65
To get your brain to appreciate the difference, in your head you can say “is equal to” when you type two equal signs. Despite this reminder, it’s still easy to goof up, especially in a conditional statement.

When you assign a value in a conditional statement, you generally create a TRUE condition unless the result of the assignment is zero:

if(here=there)
This if statement evaluates to the value of variable there. If it’s 0, the if condition evaluates as FALSE; otherwise, it’s true. Regardless, it’s most likely not what you intended. Most compilers, such as clang, catch this mistake.

Dangerous loop semicolons in your C code

You can get into a rut when you’re typing code, using the semicolon as a prefix before typing the Enter key to end a line. This practice has unintended consequences! It’s especially toxic when you code loops:
for(x=0;x<10;x++);
This loop works, but its statements aren’t repeated. When it’s done, the value of variable x is 10. That’s it.

The same problem exists for a while loop:

while(c<255);
This loop may spin endlessly, depending on the value of variable c. If the value is greater than or equal to 255, the loop won’t execute. Otherwise, it executes forever.

These semicolons are unintentional and unwanted. They’re also perfectly legitimate; the compiler doesn’t flag them as errors, though you may see a warning — which is quite helpful. For example, the suggested resolution is to place the semicolon on the next line:

while(putchar(*(ps++)))
    ;
This sole semicolon on a line by itself shouts to the compiler, as well as to any programmer reading the code, that the while loop is intentionally empty.

Commas in a C for loop

The three items in a for loop’s parentheses are separated by semicolons. Both those semicolons are required, and they are not commas. The compiler doesn’t like this statement:
for(a=0,a<10,a++)
Because commas are allowed in a for statement, the compiler merely thinks that you’ve omitted the last two required items. In fact, the following is a legitimate for statement:

The preceding statement assigns the value 0 to variable a, generates a TRUE comparison (which is ignored), and increments the value of a to 1. Then, because the second and third items are empty, the loop repeats endlessly. (Well, unless a break statement belongs to the loop.)

Missing break in a switch structure

It’s perfectly legitimate to write a switch structure where the execution falls through from one case statement to the other:

In this example, the first five case conditions capture the same set of statements. When you forget the break, however, execution falls through with more tests and, eventually, the default. Unless this control is what you want, remember to add break statements as necessary.

Suppose that you have a switch structure that’s several dozen lines high. One case condition has multiple rows of statements, so many that it scrolls up and off the screen. In such a setup, it’s easy to forget the break as you concentrate instead on crafting the proper statements. I know — I’ve done it.

Another situation happens when you code a loop inside a switch structure and you use break to get out of that loop. This inner break escapes from the for loop, only: A second break is required in order to get out of the switch structure.

Many editors, such as the one used in Code::Blocks, let you collapse and expand parts of your code. To make this feature work in a switch structure, you must enclose the case statements in curly brackets.

Missing parentheses and curly brackets in your C code

Forgetting a parenthesis or two is one of the most common C coding mistakes. The compiler catches it, but usually the error isn’t flagged until the end of the function.

For example, a missing parenthesis in the main() function causes the error to be flagged at the final line of the function. This warning is a good clue to a missing parenthesis or curly bracket, but it doesn’t help you locate it.

Today’s editors are good at matching up parentheses and brackets. For example, the Code::Blocks editor inserts both characters when you type the first one. This feature helps keep things organized. Other editors, such as vim, highlight both sets of brackets when the cursor hovers over one. Use these hints as you type to ensure that things match up.

Another editor clue is that the formatting, text coloring, and indents screw up when you forget a parenthesis or bracket. The problem with recognizing this reminder is that the human brain automatically assumes that the editor has screwed up. So you need to train yourself to recognize improper indentation by the editor as a sign of a missing parenthesis or curly bracket.

Don’t ignore a warning from your C program

When the compiler generates a warning, the program (or object code) is still created. This condition can be dangerous, especially when dealing with pointer errors. The problem is that warnings can be ignored; the code compiles anyway.

For example, you may be using printf() to display a value that you know is an int, but somehow the compiler insists that it’s some other value. If so, you can typecast the variable as an int. For example:

printf("%-14s %5ld %s",
    file->d_name,
    (long)filestat.st_size,
    ctime(&filestat.st_mtime));
In this example, the filestate.st_size variable is of the off_t data type. The printf() function lacks a conversion character for off_t, so it has typecast it to a long int. Similar typecasting can be done with other variable types for which printf() lacks a conversion character. But before you go nuts with this trick, check the man page for printf() to ensure that the specific data type lacks a conversion character.
  • A common warning happens when you try to display a long int value by using the %d When that happens, just edit %d to %ld.
  • An “lvalue required” warning indicates that you’ve written a malformed equation. The lvalue is the left value, or the item on the left side of the equation. It must be present and be of the proper type so that the equation is properly handled.
  • The degree to which the compiler flags your code with warnings can be adjusted. Various flags are used to adjust the compiler’s warning level. These flags are set in the Code::Blocks IDE by choosing the Project→Build Options command. The Compiler Flags tab in the Project Build Options dialog box lets you set and reset the various warnings.
  • The “turn on all warnings” option for a command-line C compiler is the -Wall It looks like this: clang -Wall source.c
- Wall stands for “warnings, all.”

Endless loops in C

There’s got to be a way outta here, which is true for just about every loop. The exit condition must exist. In fact, it’s highly recommended that when you set out to code a loop, the first thing you code is the exit condition. As long as it works, you can move forward and write the rest of the joyous things that the loop does.

Unintentional endless loops do happen. C programmers run code many times, only to watch a blank screen for a few moments. Oops.

Console applications, such as the kind created throughout this book, are halted by pressing the Ctrl+C key combination in a terminal window. This trick may not always work, so you can try closing the window. You can also kill the task, which is a process that’s handled differently by every operating system. For example, in a Unix operating system, you can open another terminal window and use the kill command to rub out a program run amok in the first terminal window.

scanf() blunders in C

The scanf() function is a handy way to read specific information from standard input. It’s not, however, ideal for all forms of input.

For example, scanf() doesn’t understand when a user types something other than the format that’s requested. Specifically, you cannot read in a full string of text. This issue is because scanf() discards any part of the string after the first white space character.

Though the fgets() function is a great alternative for capturing text, keep in mind that it can capture the newline that ends a line of text. This character, \n, becomes part of the input string.

The other thing to keep in mind when using scanf() is that its second argument is an address, a pointer. For standard variable types — such as int, float, and double — you must prefix the variable name with the &, the address operator:

scanf("%d",&some_int);
The & prefix isn’t necessary for reading in an array:
scanf("%s",first_name);
Individual array elements, however, aren’t memory locations, and they still require the & prefix:
scanf("%c",&first_name[0]);
Pointer variables do not require the & prefix, which could result in unintended consequences.

Streaming input restrictions in C

The basic input and output functions in the C language aren’t interactive. They work on streams, which are continuous flows of input or output, interrupted only by an end-of-file marker or, occasionally, the newline character.

When you plan to read only one character from input, be aware that the Enter key, pressed to process input, is still waiting to be read from the stream. A second input function, such as another getchar(), immediately fetches the Enter key press (the \n character). It does not wait, as an interactive input function would.

  • If you desire interactive programs, get a library with interactive functions, such as the NCurses library.
  • The end-of-file marker is represented by the EOF constant, defined in the h header file.
  • The newline character is represented by the \n escape sequence.

The newline character’s ASCII value may differ from machine to machine, so always specify the escape sequence \n for the newline.

Want to learn more? Check out our C Programming Cheat Sheet.

About This Article

This article can be found in the category: