Overview
The0x03-debugging module teaches essential debugging skills. You’ll learn to identify bugs, use debugging tools, fix logic errors, and handle edge cases. Debugging is a critical skill - writing code is only half the job; finding and fixing bugs is the other half.
What is Debugging?
Debugging is the process of finding and fixing errors (bugs) in your code. Common bug types include:- Syntax errors: Code that doesn’t compile
- Logic errors: Code that compiles but produces wrong results
- Runtime errors: Code that crashes during execution
- Edge case errors: Code that fails with specific inputs
Header File for Debugging
main.h
The
#ifndef, #define, and #endif directives create an include guard, preventing the header from being included multiple times.Testing Functions
Test Case - Zero Value
0-main.c
Fixing Infinite Loops
The Bug
Infinite loops are common errors where the loop condition never becomes false:The Fix
1-main.c
Commenting out problematic code with
/* */ is one debugging technique. The code is preserved for reference but won’t execute.Logic Errors
Finding the Largest Number
Logic errors are subtle - the code compiles but produces incorrect results.2-largest_number.c
Analyzing the logic
Analyzing the logic
Edge case issue: What if two or all three numbers are equal?
-
If
a = 5, b = 5, c = 3:- First condition fails:
a > bis false - Second condition fails:
b > ais false - Third condition:
c > bis false - Falls to
else: returnsb(correct!)
- First condition fails:
-
If
a = 5, b = 3, c = 5:- First condition fails:
a > cis false - Second condition fails:
b > ais false - Third condition:
c > bis true - Returns
c(correct!)
- First condition fails:
else clause handles equal values correctly.Complex Debugging - Leap Years
Date Validation Bug
3-print_remaining_days.c
Understanding Leap Year Logic
- Leap Year Rules
- Day Adjustment
- Invalid Date
A year is a leap year if:
- Divisible by 4 AND
- NOT divisible by 100 OR
- Divisible by 400
- 2000: Leap year (divisible by 400)
- 1900: Not leap year (divisible by 100, not by 400)
- 2024: Leap year (divisible by 4, not by 100)
The expression
(year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) uses operator precedence:&&binds tighter than||- Equivalent to:
((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)
Debugging Techniques
1. Print Debugging
Add printf statements to track values:2. Rubber Duck Debugging
Explain your code line-by-line to someone (or a rubber duck). Often, you’ll spot the bug while explaining.3. Binary Search Debugging
Comment out half the code to isolate which section contains the bug:4. Test Edge Cases
Common Bug Patterns
Off-by-one errors
Off-by-one errors
Uninitialized variables
Uninitialized variables
Comparison vs Assignment
Comparison vs Assignment
Missing break in switch
Missing break in switch
Compilation for Debugging
The
-g flag includes debugging information that tools like gdb can use.Using GDB (GNU Debugger)
Best Debugging Practices
Testing Checklist
Before considering code complete:- Test with normal inputs
- Test with edge cases (0, negative, maximum)
- Test with invalid inputs
- Test with equal values
- Check for memory leaks
- Verify all return paths
- Check loop boundaries
- Compile with all warnings enabled
Prevention is Better Than Cure
Write code to avoid bugs:
- Initialize all variables
- Check function return values
- Validate input parameters
- Use meaningful variable names
- Keep functions simple and focused
- Comment complex logic