15 Common C Language Pitfalls Every Developer Should Avoid
This article enumerates fifteen frequent C programming traps—from operator precedence and case‑sensitivity to pointer misuse and multithreading issues—provides clear code examples, explains why each error occurs, and offers practical solutions plus a challenging interview question.
C is a widely used programming language, but its low‑level nature makes it prone to subtle bugs that can cause crashes, data loss, or security vulnerabilities. The following list presents fifteen common C pitfalls, each illustrated with code and a recommended fix.
1. Operator Precedence
Misunderstanding the precedence of operators such as ++, --, and * can lead to unexpected results.
int a = 5, b = 3;
int c = a++ * --b; // a becomes 6, b becomes 2, c = 10Solution: learn the precedence rules and use parentheses to make the intended order explicit.
2. Case Sensitivity
Variable and function names are case‑sensitive; myVar and MyVar are distinct identifiers.
int MyVar = 5;
int myvar = 3;
printf("%d
", MyVar + myvar); // prints 8Solution: adopt a consistent naming convention and stick to it.
3. Array Out‑of‑Bounds
Accessing an element outside an array’s defined range leads to undefined behavior.
int arr[3] = {1, 2, 3};
int x = arr[3]; // out‑of‑bounds accessSolution: always check that an index is within 0 and size‑1.
4. Integer Overflow
When an integer exceeds its representable range, it wraps around.
unsigned char x = 255;
x += 1; // x becomes 0Solution: choose data types that can hold the expected range or add explicit checks.
5. Null Pointer Dereference
Using a pointer that is NULL results in a runtime fault.
int *p = NULL;
*p = 5; // error: dereferencing null pointerSolution: verify a pointer is non‑null before dereferencing.
6. Random Number Seed
Calling rand() without seeding produces the same sequence each run.
for (int i = 0; i < 10; i++) {
printf("%d ", rand()); // same numbers each execution
}
// Proper seeding
srand(time(NULL));Solution: seed the generator with a varying value such as the current time.
7. String Handling
Strings in C are null‑terminated character arrays; forgetting the terminator or writing past the buffer yields undefined output.
char str[10] = "hello";
str[5] = 'w'; // missing '\0'
printf("%s
", str); // may print garbage after "hellow"
// Correct fix
str[5] = 'w';
str[6] = '\0';Solution: always ensure a terminating '\0' after modifications.
8. Loop Condition Errors
An incorrect loop condition can cause infinite loops or skip execution entirely.
int i = 0;
while (i < 10) {
printf("%d ", i);
// missing i++ leads to infinite loop
}Solution: verify that loop variables are updated and the condition will eventually become false.
9. Variable Scope
Variables declared inside a block are not visible outside it.
int x = 1;
if (x == 1) {
int y = 2;
}
printf("%d
", y); // error: y out of scopeSolution: declare variables in the appropriate scope for their intended use.
10. Implicit Type Conversion
Mixing integer and floating‑point types can produce surprising results due to implicit conversion.
int a = 5;
double b = 2.0;
printf("%f
", a / b); // prints 2.000000 (integer division first)
// Correct cast
printf("%f
", (double)a / b); // prints 2.500000Solution: cast explicitly when mixing types.
11. Function Call Mismatch
Providing the wrong number or type of arguments triggers compilation errors.
int add(int a, int b) { return a + b; }
printf("%d
", add(1, 2, 3)); // too many argumentsSolution: match the function prototype exactly.
12. Structure Access Errors
Dereferencing a null pointer to a struct or accessing a non‑existent member causes crashes.
struct Person { char name[10]; int age; } *p = NULL;
printf("%s
", p->name); // null‑pointer dereferenceSolution: check pointers for NULL before use.
13. File Operation Mistakes
Failing to verify the success of fopen() before using the file handle can lead to errors.
FILE *fp = fopen("test.txt", "r");
// If fp is NULL, fclose(fp) is unsafe
fclose(fp);Solution: test the return value of fopen() and handle failures gracefully.
14. Macro Definition Pitfalls
Macros without proper parentheses can produce unexpected operator precedence.
#define SQUARE(x) x * x
int a = 2;
int b = SQUARE(a + 1); // expands to a + 1 * a + 1Solution: wrap macro parameters and the entire replacement list in parentheses: #define SQUARE(x) ((x) * (x)).
15. Multithreading Synchronization
Concurrent threads accessing shared resources like printf() without synchronization may interleave output.
void *print_message(void *ptr) {
char *msg = (char *)ptr;
printf("%s
", msg);
pthread_exit(NULL);
}
pthread_create(&t1, NULL, print_message, (void *)"Thread 1");
pthread_create(&t2, NULL, print_message, (void *)"Thread 2");Solution: protect shared resources with mutexes or other synchronization primitives.
Interview Question
Consider the following code snippet:
int a = 0, b = 1, c = 2, d = 3;
if (a++ && b-- || c++ && d--) {
printf("case - %d %d %d %d
", a, b, c, d);
} else {
printf("case + %d %d %d %d
", a, b, c, d);
}What will be printed and why? The expression evaluates left‑to‑right with short‑circuit rules: a++ yields 0 (false), so the && b-- part is skipped; the || then evaluates c++ && d--, where c++ is non‑zero (true) and d-- is evaluated, resulting in d becoming 2. The overall condition is true, so the if branch runs, printing case - 1 1 3 2.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
