C Debugging Techniques
In this page:
Printf Debugging
Inserting printf() calls at key points in your code to print the current values of variables is the simplest and most universal debugging technique in C, requiring no special tools, though it does mean remembering to remove or comment out the extra output before shipping the final program.
Example: Printf Debugging
#include <stdio.h>
int main() {
int x = 5;
printf("DEBUG: x = %d\n", x);
x = x * 2;
printf("%d", x);
return 0;
}
Login to try C/C++/Java/PHP code in the editor
Using Predefined Macros
The predefined macros __FILE__ and __LINE__ expand automatically to the current source file's name and the current line number, so embedding them in a debug print (e.g. printf("%s:%d value=%d\n", __FILE__, __LINE__, value);) tells you exactly where a given message came from without typing it manually.
Example: Using Predefined Macros
#include <stdio.h>
int main() {
int value = 5;
printf("%s:%d value=%d\n", __FILE__, __LINE__, value);
return 0;
}
Login to try C/C++/Java/PHP code in the editor
Conditional Debug Blocks
Wrapping debug output inside #ifdef DEBUG ... #endif blocks lets you compile the exact same source file with verbose diagnostic printing enabled for development builds and completely stripped out for release builds, just by defining or omitting the DEBUG macro at compile time.
Example: Conditional Debug Blocks
#include <stdio.h>
#define DEBUG
int main() {
#ifdef DEBUG
printf("Debug output enabled\n");
#endif
printf("Normal output");
return 0;
}
Login to try C/C++/Java/PHP code in the editor
Pointer Safety Checks
An uninitialized pointer holds whatever garbage address happened to be left in memory, so dereferencing it can crash unpredictably or, worse, silently corrupt unrelated memory. Initializing every pointer to NULL immediately and checking for NULL before dereferencing turns a random crash into a predictable, debuggable one.
Example: Pointer Safety Checks
#include <stdio.h>
int main() {
int *ptr = NULL;
if (ptr == NULL) {
printf("Pointer not initialized safely -- avoided dereference");
}
return 0;
}
Login to try C/C++/Java/PHP code in the editor
Dry Run Loop Traces
Off-by-one and boundary errors are among the most common loop bugs in C, so printing the loop index on every iteration while debugging quickly reveals whether a loop is running one time too many, one time too few, or accessing an index outside the array's valid range.
Example: Dry Run Loop Traces
#include <stdio.h>
int main() {
for (int i = 0; i < 3; i++) {
printf("Loop index: %d\n", i);
}
return 0;
}
Login to try C/C++/Java/PHP code in the editor
Chapter Quiz — Complete all 20 topics to unlock
0/20 topics done
Complete these topics first:
- C typedef
- C Type Casting
- C Bit Fields
- C Variable Length Arrays
- C Command Line Arguments
- C Function Pointers
- C Callback Functions
- C Multidimensional Pointer
- C string.h Functions
- C stdlib.h Functions
- C math.h Functions
- C time.h Functions
- C ctype.h Functions
- C errno.h
- C assert.h
- C Error Handling
- C Debugging Techniques
- C Code Style & Best Practices
- C Common Mistakes
- C Interview Questions