C Errors and Debugging
Every programmer writes bugs. What makes a good programmer is finding them quickly. C gives three kinds of feedback: the compiler's errors and warnings, problems while the program runs, and wrong results.
Compiler errors and warnings
An error stops the build: the program cannot be made until it is fixed. A warning lets the build continue but points at code that is very likely wrong. Always compile with -Wall and treat warnings as errors to fix. Read the first message first: later ones are often caused by the first.
A message has the form file:line:column: error: text. In our editor, clicking it jumps to the line, and a hint in plain words follows it.
| Message | Usual cause |
|---|---|
expected ';' | a semicolon is missing at the end of the line above |
use of undeclared identifier | a typo in a name, or a variable declared later or in another block |
call to undeclared function | a missing #include or prototype |
format specifies type 'int *' | & is missing in scanf |
variable is uninitialized | the variable is used before it gets a value |
Runtime errors
Some mistakes only show when the program runs: dividing by zero, an array index outside the array, using a NULL or freed pointer, or recursion that never stops. C itself does not check most of them, so the program may crash or quietly produce garbage. Turn on Safe mode in the editor's Options: it stops the program at such a mistake and names the function.
#include <stdio.h>
int main(void) {
int a[3] = {1, 2, 3};
int sum = 0;
for (int i = 0; i < 3; i++) { // try changing < to <= with Safe mode on
sum += a[i];
}
printf("sum = %d\n", sum);
return 0;
}sum = 6
printf debugging
When the result is wrong, print the values that lead to it. Add printf lines that show variables inside a loop, run, compare with what you expected, and narrow down where the first wrong value appears. Remove the extra lines when you are done, or keep them behind #if DEBUG.
assert
assert(condition) from assert.h stops the program with a message when a condition that must always be true is false. It documents your assumptions and catches broken ones early:
#include <assert.h>
#include <stdio.h>
double average(const int a[], int n) {
assert(n > 0); // dividing by zero would be a bug
int sum = 0;
for (int i = 0; i < n; i++) sum += a[i];
return (double)sum / n;
}
int main(void) {
int marks[] = {70, 80, 90};
printf("%.1f\n", average(marks, 3));
return 0;
}80.0
Classic beginner mistakes
=instead of==in a condition.- A semicolon right after
if (...)orfor (...), which makes the body empty. - Forgetting
breakin aswitch. - Loops that run one time too many (
<=instead of<). - Integer division where a decimal result was wanted.
- Strings: forgetting room for
'\0', comparing with==instead ofstrcmp.
Practice exercises
- Put a semicolon right after
for (int i = 0; i < 3; i++)in the example above, run it and explain the result. - Add
assert(n > 0)to a function of your own and call it with 0. - With Safe mode on, read
a[3]from the example array and read the message.