Debugging Like a Detective
Finding and fixing bugs — the skill that separates good from great!
Open interactive version (quiz + challenge)Real-world analogy
What is it?
Debugging is the art of finding and fixing errors in your code. It's arguably the most important practical skill in competitive programming. This lesson covers the most common bugs (off-by-one, overflow, uninitialized variables), systematic debugging techniques (print statements, edge case testing), and good habits that prevent bugs in the first place.
Real-world relevance
The term 'bug' in computing dates back to 1947 when a moth got stuck in the Harvard Mark II computer. Grace Hopper's team literally found a bug! Today, companies like Google and NASA spend enormous resources on testing and debugging. The Ariane 5 rocket exploded in 1996 because of an integer overflow — a bug that cost $370 million!
Key points
- Off-By-One Errors — The most common bug in programming! Using < instead of <=, starting at 0 instead of 1, or looping one too many or too few times. Example: 'for (int i = 0; i <= n; i++)' when the array only has indices 0 to n-1. Always double-check your loop boundaries!
- Uninitialized Variables — If you declare a variable but don't give it a value, it contains garbage data — a random value from memory. In C++, 'int sum;' might be 0 or might be -1294832. Always initialize: 'int sum = 0;' This bug is sneaky because it might work on your computer but fail on the judge!
- Integer Overflow — int can hold up to about 2 billion (2 × 10^9). If your calculation exceeds this, the number wraps around and gives a wrong (often negative) answer. Use 'long long' for big numbers (up to about 9 × 10^18). Common trap: n * n when n = 100000 overflows int!
- Print Debugging — Your Best Tool — When your code gives wrong output, add cout statements to see what's happening inside. Print variable values, loop counters, intermediate results. 'cerr << "i=" << i << " sum=" << sum << endl;' Use cerr (not cout) so it doesn't interfere with your output!
- Edge Cases to Always Check — n = 0 (empty input), n = 1 (single element), negative numbers, maximum values (10^9, 10^18), all elements the same, already sorted input, reverse sorted input. These corner cases catch most bugs! Always test them before submitting.
- Reading Input Wrong — If your code reads input in the wrong order or reads the wrong number of values, everything else breaks. Always match your cin statements EXACTLY to the input format. If the problem says 'first line: n, second line: n integers,' make sure you read them in that exact order.
- Testing Before Submitting — Never submit without testing! Run your code on ALL the given examples first. Then make up your own test cases, especially edge cases. If all examples pass but you get WA, your code probably fails on an edge case you didn't think of.
- Common Runtime Errors — Division by zero (always check before dividing). Array out of bounds (accessing a[-1] or a[n]). Stack overflow (infinite recursion or very deep recursion). These cause Runtime Error (RE) on the judge. Add checks for these scenarios!
- The Rubber Duck Method — When stuck, explain your code line-by-line to a rubber duck (or imaginary friend). Seriously! The act of explaining forces you to think through every step. Many programmers find the bug the moment they start explaining. It sounds silly but it WORKS!
Code example
#include <bits/stdc++.h>
using namespace std;
int main() {
// EXAMPLE: Find the maximum subarray sum (common CP problem)
// Let's debug it step by step!
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) cin >> a[i];
// Kadane's algorithm (simplified)
long long maxSum = a[0]; // NOT 0! (what if all negative?)
long long currentSum = a[0]; // Start with first element
cerr << "Starting: maxSum=" << maxSum << " currentSum=" << currentSum << "\n";
for (int i = 1; i < n; i++) { // Start from 1, not 0!
currentSum = max((long long)a[i], currentSum + a[i]);
maxSum = max(maxSum, currentSum);
// Debug print — comment out before submitting!
cerr << "i=" << i << " a[i]=" << a[i]
<< " currentSum=" << currentSum
<< " maxSum=" << maxSum << "\n";
}
cout << maxSum << "\n";
// === DEBUGGING CHECKLIST ===
// 1. Did I read all input correctly?
// 2. Are my loop bounds right (no off-by-one)?
// 3. Did I initialize all variables?
// 4. Can any calculation overflow int?
// 5. Did I handle edge cases (n=1, all negative)?
// 6. Does my output match the required format?
// 7. Did I test with ALL given examples?
return 0;
}Line-by-line walkthrough
- 1. vector a(n); — we use a vector instead of int a[n] to avoid variable-length array issues on some compilers.
- 2. long long maxSum = a[0]; — we initialize to the first element, NOT 0! If all numbers are negative (like -3, -1, -5), the answer is -1, not 0. Initializing to 0 would be a bug.
- 3. long long currentSum = a[0]; — same here. We also use long long to prevent integer overflow when numbers are large.
- 4. for (int i = 1; i < n; i++) — we start from index 1, not 0, because we already used a[0] for initialization. Starting from 0 would process a[0] twice.
- 5. currentSum = max((long long)a[i], currentSum + a[i]); — at each step, we choose: start fresh from a[i], or extend the current subarray. This is Kadane's algorithm!
- 6. cerr << ... — debug output goes to cerr (standard error), which is separate from cout (standard output). The judge only looks at cout, so cerr won't cause Wrong Answer. Remove or comment out before submitting for cleaner code.
- 7. The debugging checklist at the bottom covers the most common sources of bugs. Going through this checklist before submitting can save you many Wrong Answer penalties!
Spot the bug
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
int a[n];
for (int i = 0; i < n; i++) cin >> a[i];
long long sum;
for (int i = 0; i < n; i++) {
sum += a[i];
}
cout << sum << "\n";
return 0;
}Need a hint?
Show answer
Explain like I'm 5
Fun fact
Hands-on challenge
More resources
- Common Mistakes in Competitive Programming (Codeforces Blog)
- Debugging Tips for Competitive Programming (Errichto)
- Practice with Tricky Edge Cases (Codeforces)