Common C++ Mistakes

Learn from these common pitfalls to write better code

Array and Index Mistakes

Off-by-One Errors in Loops

Array
Wrong
for (int i = 0; i <= n; i++) {
    arr[i] = 0;  // Buffer overflow!
}
Correct
for (int i = 0; i < n; i++) {
    arr[i] = 0;  // Safe access
}

Why This Happens

Arrays are 0-indexed. An array of size n has valid indices 0 to n-1. Using <= instead of < accesses index n, which is out of bounds.

Integer Overflow in Midpoint Calculation

Binary Search
Wrong
int mid = (left + right) / 2;
// Overflow when left + right > INT_MAX
Correct
int mid = left + (right - left) / 2;
// Safe from overflow

Why This Happens

When left and right are both large (close to INT_MAX), their sum overflows. The correct formula avoids adding them directly.

Accessing Empty Container

STL
Wrong
vector v;
int x = v[0];     // Undefined behavior!
int y = v.back(); // Also undefined!
Correct
vector v;
if (!v.empty()) {
    int x = v[0];
    int y = v.back();
}

Why This Happens

Always check if a container is empty before accessing elements. This is especially important for stacks, queues, and vectors.

Pointer and Memory Mistakes

Dereferencing NULL Pointer

Pointer
Wrong
TreeNode* root = nullptr;
int val = root->val;  // Crash!
Correct
TreeNode* root = nullptr;
if (root != nullptr) {
    int val = root->val;
}

Why This Happens

In tree/linked list problems, always check for null before accessing members. This is the most common cause of runtime errors.

Forgetting to Move Pointer in Linked List

Linked List
Wrong
while (curr != nullptr) {
    curr->val *= 2;
    // Forgot curr = curr->next;
    // Infinite loop!
}
Correct
while (curr != nullptr) {
    curr->val *= 2;
    curr = curr->next;
}

Memory Leak - Forgetting to Delete

Memory
Wrong
int* arr = new int[100];
// ... use arr ...
// Memory leak - forgot delete[] arr;
Correct
// Use vector instead
vector arr(100);
// Or use smart pointers
unique_ptr arr(new int[100]);

Best Practice

In competitive programming, use STL containers. In production, prefer smart pointers (unique_ptr, shared_ptr) over raw pointers.

STL Mistakes

Modifying Container While Iterating

Iterator
Wrong
for (auto it = v.begin(); it != v.end(); it++) {
    if (*it == target) {
        v.erase(it); // Iterator invalidated!
    }
}
Correct
// Method 1: erase returns new iterator
for (auto it = v.begin(); it != v.end(); ) {
    if (*it == target) it = v.erase(it);
    else ++it;
}

// Method 2: Use erase-remove idiom
v.erase(remove(v.begin(), v.end(), target), v.end());

Using Wrong Comparator for Priority Queue

Heap
Confusing
// Default is MAX heap
priority_queue pq;

// For MIN heap, need this:
priority_queue, greater> minPq;
Remember
// For custom types:
struct Compare {
    bool operator()(const pair& a, 
                    const pair& b) {
        return a.first > b.first; // Min heap
    }
};
priority_queue, vector>, Compare> pq;

Key Point

The comparator logic is opposite of what you might expect. Use greater<int> for min-heap, less<int> (default) for max-heap.

Passing Large Containers by Value

Performance
Wrong
void process(vector nums) {  // Copies entire vector!
    // ...
}
Correct
void process(const vector& nums) {  // Reference
    // ...
}

void modify(vector& nums) {  // Non-const if modifying
    // ...
}

Logic Mistakes

Assignment Instead of Comparison

Operator
Wrong
if (x = 5) {  // Always true! Assigns 5 to x
    // ...
}
Correct
if (x == 5) {  // Compares x with 5
    // ...
}

Integer Division Truncation

Math
Wrong
int a = 5, b = 2;
double result = a / b;  // result = 2.0, not 2.5!
Correct
int a = 5, b = 2;
double result = (double)a / b;  // result = 2.5
// Or: double result = a * 1.0 / b;

Forgetting Base Case in Recursion

Recursion
Wrong
int factorial(int n) {
    return n * factorial(n - 1);  // Stack overflow!
}
Correct
int factorial(int n) {
    if (n <= 1) return 1;  // Base case!
    return n * factorial(n - 1);
}

Performance Mistakes

Using size() in Loop Condition

Performance
Potentially Slow
for (int i = 0; i < v.size() - 1; i++) {
    // If v is empty, v.size()-1 underflows!
}
Correct
int n = v.size();
for (int i = 0; i + 1 < n; i++) {
    // Safe from underflow
}

Why This Happens

size() returns size_t (unsigned). If size is 0, subtracting 1 underflows to a huge positive number!

String Concatenation in Loop

String
O(n^2)
string result = "";
for (char c : chars) {
    result = result + c;  // Creates new string each time!
}
O(n)
string result;
result.reserve(chars.size());
for (char c : chars) {
    result += c;  // Appends in place
}