Common C Language Errors & Debugging Guide
1. Missing Semicolon Issues
Error Example:
#include <stdio.h>
int main() {
int x = 10
printf("%d", x); // ERROR: expected ';' before 'printf'
return 0;
}Solution:
#include <stdio.h>
int main() {
int x = 10; // CORRECT: Added semicolon
printf("%d", x);
return 0;
}Common Places Missing Semicolons Occur:
- After variable declarations
- After function calls
- After return statements
- After structure member declarations
- After enum declarations
2. Undefined Reference Errors
Error Example:
// undefined reference to printf
// undefined reference to mainCommon Causes:
- Missing header file includes
- Function not defined or declared
- Linking errors (missing library files)
- Spelling mistakes in function names
Solutions:
// Include required headers
#include <stdio.h> // For printf, scanf
#include <string.h> // For string functions
#include <stdlib.h> // For malloc, free
#include <math.h> // For math functions
// Declare functions before use
int add(int a, int b); // Function prototype
int main() {
int result = add(5, 3); // Now it works
return 0;
}
int add(int a, int b) { // Function definition
return a + b;
}3. Segmentation Fault Explanation
What is Segmentation Fault?
Segmentation fault (segfault) occurs when a program tries to access memory that it doesn't have permission to access. It's one of the most common runtime errors in C.
Common Causes:
a) Null Pointer Dereference:
// ERROR
int *ptr = NULL;
*ptr = 10; // Segmentation fault!
// CORRECT
int *ptr = NULL;
if (ptr != NULL) {
*ptr = 10;
} else {
printf("Pointer is NULL\n");
}b) Accessing Freed Memory:
// ERROR
int *ptr = malloc(sizeof(int) * 10);
free(ptr);
*ptr = 10; // Segmentation fault! Memory already freed
// CORRECT
int *ptr = malloc(sizeof(int) * 10);
if (ptr != NULL) {
*ptr = 10;
}
free(ptr);
ptr = NULL; // Prevent dangling pointerc) Stack Overflow:
// ERROR - Infinite recursion
int factorial(int n) {
return n * factorial(n - 1); // No base case!
}
// CORRECT
int factorial(int n) {
if (n <= 1) {
return 1; // Base case
}
return n * factorial(n - 1);
}d) Buffer Overflow:
// ERROR
char str[5];
strcpy(str, "Hello World"); // Too long! Segmentation fault
// CORRECT
char str[50];
strncpy(str, "Hello World", sizeof(str) - 1);
str[sizeof(str) - 1] = '\0';How to Debug Segmentation Faults:
- Use debugger (GDB) with:
gdb ./program - Compile with debugging symbols:
gcc -g program.c - Use Valgrind:
valgrind ./program - Add printf statements to trace execution
- Check all pointer operations
4. Pointer Errors
a) Uninitialized Pointer:
// ERROR
int *ptr;
*ptr = 10; // Pointer not initialized! Undefined behavior
// CORRECT
int *ptr;
int value = 10;
ptr = &value; // Initialize pointer
*ptr = 20; // Now safeb) Dangling Pointer:
// ERROR
int *ptr = malloc(sizeof(int) * 10);
free(ptr);
*ptr = 10; // Dangling pointer! Using freed memory
// CORRECT
int *ptr = malloc(sizeof(int) * 10);
if (ptr != NULL) {
*ptr = 10;
}
free(ptr);
ptr = NULL; // Set to NULL after freeingc) Double Free:
// ERROR
int *ptr = malloc(sizeof(int) * 10);
free(ptr);
free(ptr); // Double free error!
// CORRECT
int *ptr = malloc(sizeof(int) * 10);
free(ptr);
ptr = NULL; // Set to NULL
// Now calling free(ptr) again is safe (no error, but unnecessary)d) Wrong Pointer Type:
// ERROR
float f = 3.14;
int *ptr = &f; // Wrong type! Undefined behavior
printf("%d", *ptr);
// CORRECT
float f = 3.14;
float *ptr = &f; // Correct type
printf("%f", *ptr);e) Pointer Arithmetic Errors:
// ERROR
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr;
ptr += 10; // Out of bounds!
printf("%d", *ptr); // Undefined behavior
// CORRECT
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr;
if (ptr + 2 < arr + 5) { // Check bounds
printf("%d", *(ptr + 2)); // Safe access
}5. Array Out of Bounds
Error Example:
// ERROR
int arr[5] = {1, 2, 3, 4, 5};
arr[10] = 100; // Out of bounds! Undefined behavior
printf("%d", arr[-1]); // Negative index! Error
// CORRECT
int arr[5] = {1, 2, 3, 4, 5};
int index = 10;
if (index >= 0 && index < 5) { // Bounds checking
arr[index] = 100;
} else {
printf("Index out of bounds!\n");
}String Array Bounds:
// ERROR
char str[5];
strcpy(str, "Hello World"); // Buffer overflow!
// CORRECT
char str[50];
strncpy(str, "Hello World", sizeof(str) - 1);
str[sizeof(str) - 1] = '\0';
// Or use safer alternative
char str[50];
snprintf(str, sizeof(str), "Hello World");2D Array Bounds:
// ERROR
int matrix[3][3];
matrix[5][5] = 100; // Out of bounds!
// CORRECT
int matrix[3][3];
int row = 5, col = 5;
if (row >= 0 && row < 3 && col >= 0 && col < 3) {
matrix[row][col] = 100;
}6. Incorrect scanf Usage
a) Missing & (Address Operator):
// ERROR
int num;
scanf("%d", num); // Missing &! Undefined behavior
// CORRECT
int num;
scanf("%d", &num); // Address operator requiredb) Format Specifier Mismatch:
// ERROR
float f;
scanf("%d", &f); // Wrong format specifier! Undefined behavior
// CORRECT
float f;
scanf("%f", &f); // Correct format specifier
// For double
double d;
scanf("%lf", &d); // Use %lf for doublec) Buffer Issues with Characters:
// ERROR - Newline character in buffer
int num;
char ch;
scanf("%d", &num);
scanf("%c", &ch); // Reads newline from previous input!
// CORRECT - Add space before %c
int num;
char ch;
scanf("%d", &num);
scanf(" %c", &ch); // Space consumes newlined) String Input:
// ERROR
char str[10];
scanf("%s", &str); // Don't use & with strings!
// CORRECT
char str[10];
scanf("%s", str); // String name is already address
// Better - limit input length
scanf("%9s", str); // Read max 9 characters (leave space for '\0')e) Not Checking Return Value:
// ERROR - No validation
int num;
scanf("%d", &num); // What if user enters non-integer?
// CORRECT - Check return value
int num;
if (scanf("%d", &num) == 1) {
printf("Valid input: %d\n", num);
} else {
printf("Invalid input!\n");
}7. Logical Errors
a) Using = instead of ==:
// ERROR - Always true (assignment returns assigned value)
int x = 5;
if (x = 10) { // Assigns 10 to x, always true!
printf("x is 10\n");
}
// CORRECT
int x = 5;
if (x == 10) { // Comparison operator
printf("x is 10\n");
}b) Off-by-One Errors:
// ERROR - Array index starts from 0, not 1
int arr[5] = {1, 2, 3, 4, 5};
for (int i = 1; i <= 5; i++) { // Accesses arr[5] which is out of bounds
printf("%d ", arr[i]);
}
// CORRECT
int arr[5] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) { // Correct: 0 to 4
printf("%d ", arr[i]);
}c) Infinite Loops:
// ERROR - Condition never becomes false
int i = 0;
while (i < 10) {
printf("%d ", i);
// Missing i++!
}
// CORRECT
int i = 0;
while (i < 10) {
printf("%d ", i);
i++; // Increment counter
}d) Operator Precedence Issues:
// ERROR - Wrong precedence
int result = 2 + 3 * 4; // You might expect 20, but it's 14
// Because * has higher precedence than +
// CORRECT - Use parentheses for clarity
int result = (2 + 3) * 4; // Now it's 208. Flowchart/Debugging Tips
Systematic Debugging Approach:
- Understand the Error:
- Read compiler error messages carefully
- Check line numbers mentioned in errors
- Understand what the error means
- Isolate the Problem:
- Comment out code sections to find the problem area
- Test with simple input values
- Check each function separately
- Add Debug Output:
// Add printf statements printf("DEBUG: Entering function\n"); printf("DEBUG: Value of x = %d\n", x); printf("DEBUG: Value of ptr = %p\n", ptr); - Use Compiler Warnings:
- Compile with:
gcc -Wall -Wextra program.c - Fix all warnings (they often indicate problems)
- Compile with:
- Use Debugger:
- GDB for Linux:
gdb ./program - Set breakpoints and step through code
- Inspect variable values at runtime
- GDB for Linux:
Common Debugging Tools:
- Compiler Flags: -Wall, -Wextra, -Werror, -g
- Valgrind: Memory leak detector
- GDB: GNU Debugger
- Static Analyzers: cppcheck, clang-analyzer
Prevention Tips:
- Always initialize variables
- Check pointers for NULL before use
- Validate array bounds before access
- Free dynamically allocated memory
- Use meaningful variable names
- Add comments for complex logic
- Test with boundary values
⚠️ Important
Always compile with warnings enabled: gcc -Wall -Wextra -g program.c. Most errors can be caught at compile time. Fix warnings immediately to prevent runtime errors.
Summary
| Error Type | Common Causes | Severity |
|---|---|---|
| Missing Semicolon | Forgetting semicolon after statements | Compile Error |
| Segmentation Fault | Null pointer, buffer overflow, accessing freed memory | Runtime Error |
| Pointer Errors | Uninitialized, dangling, null pointer dereference | Runtime Error |
| Array Out of Bounds | Accessing array beyond allocated size | Runtime Error |
| Logical Errors | Using = instead of ==, off-by-one, infinite loops | Logic Error |
Frequently Asked Questions
Q1: What is the most common error in C programming?
Missing semicolons are the most common compile-time errors. Segmentation faults from null pointer dereference and array out-of-bounds are the most common runtime errors. Logical errors like using = instead of == are also very common and can be hard to detect.
Q2: How do I debug a segmentation fault?
Use GDB debugger: compile with -g flag, run gdb ./program, use runto execute, bt for backtrace. Check for null pointers, array bounds, and freed memory access. Use Valgrind to detect memory errors: valgrind ./program.
Q3: Why does my program crash with "Segmentation fault (core dumped)"?
This occurs when accessing invalid memory. Common causes: dereferencing NULL pointer, accessing array out of bounds, using freed memory, stack overflow from infinite recursion, or buffer overflow. The OS terminates the program to prevent memory corruption. Use debugger to find exact line causing the crash.
Q4: How can I prevent pointer errors?
Always initialize pointers (set to NULL or valid address), check for NULL before dereferencing, set pointer to NULL after free(), avoid using freed memory, be careful with pointer arithmetic, and use tools like Valgrind to detect pointer misuse. Initialize pointers at declaration: int *ptr = NULL;.
Q5: What compiler flags should I use for debugging?
Use -Wall -Wextra to enable all warnings, -gfor debug symbols (enables GDB), -O0 to disable optimization for easier debugging. Full command: gcc -Wall -Wextra -g -O0 program.c. Fix all warnings before running.
Q6: How do I find memory leaks in my C program?
Use Valgrind: valgrind --leak-check=full ./program. It reports memory leaks, invalid memory access, and use of uninitialized values. Ensure every malloc/calloc has a corresponding free(). Set pointers to NULL after freeing. Review Valgrind output carefully to identify leaked memory locations.
Q7: What is the difference between compile-time and runtime errors?
Compile-time errors occur during compilation (syntax errors, missing semicolons, undefined variables). Runtime errors occur during program execution (segmentation faults, division by zero, null pointer access). Compile-time errors prevent program from running, while runtime errors cause program to crash or behave incorrectly during execution.
Q8: How do I debug an infinite loop?
Add printf statements inside loop to see variable values and verify loop condition. Check if loop variable is being incremented/decremented. Verify loop condition will eventually become false. Use debugger to set breakpoint and step through loop. Look for missing increment statements or conditions that never change. Use Ctrl+C to interrupt infinite loop.
Conclusion
Debugging is an essential skill for C programmers. Understanding common errors and their causes helps you write better code and fix issues more efficiently. Most errors can be prevented by following best practices: always initialize variables, check pointers for NULL, validate array bounds, and compile with warnings enabled.
Systematic debugging approaches, combined with proper tools like GDB and Valgrind, make the debugging process much more manageable. Remember that debugging is part of the learning process - every error you fix makes you a better programmer. Take time to understand why errors occur, not just how to fix them.
Related Links
🔹 Author: Dr. J. Siva Ramakrishna
🔹 Institution: Narayana Engineering College, Gudur
🔹 Last Updated: 9 January 2026