Chapter 16: Common Best Practices & Debugging
Writing code is one thing, but writing clean, safe, readable, and bug-free code is what separates good programmers from great ones.
In this chapter we will learn:
- Coding style and conventions (how to write beautiful code)
- Common errors beginners make (and how to avoid them)
- Debugging techniques (how to find and fix bugs)
- Memory management tips (very critical in C)
1. Coding Style and Conventions
Good style makes your code easy to read, understand, and maintain.
Golden Rules (Follow these always!)
A. Use meaningful variable and function names
- Bad: int x, y, z;
- Good: int studentAge, totalMarks, maxScore;
B. Consistent indentation & braces style
- Always use 4 spaces or 1 tab for indentation
- Use Allman style (opening brace on new line) or K&R style (opening brace on same line) – be consistent!
Good example (Allman style):
|
0 1 2 3 4 5 6 7 8 9 10 |
int calculateSum(int a, int b) { int sum = a + b; return sum; } |
C. Add comments – but only when needed
- Comment why you did something, not what (what is obvious from code)
|
0 1 2 3 4 5 6 7 |
// Calculate average – use float to avoid integer division average = (float)total / count; |
D. Keep functions small (ideally < 50 lines)
- One function = one responsibility
E. Use consistent naming conventions
- Variables & functions: camelCase or snake_case (choose one)
- Good: studentName, calculate_average
- Constants: ALL_CAPS
C01234567#define MAX_STUDENTS 100const int MAX_MARKS = 100;
F. Header & source file separation
- Put function prototypes and structure definitions in .h file
- Put function definitions in .c file
G. Always initialize variables
|
0 1 2 3 4 5 6 7 |
int count = 0; // Good int count; // Bad – garbage value |
2. Common Errors Beginners Make (and How to Fix Them)
A. Forgetting semicolon (;)
|
0 1 2 3 4 5 6 |
printf("Hello") // Error! |
B. Forgetting & in scanf()
|
0 1 2 3 4 5 6 7 |
scanf("%d", age); // Wrong! Program crashes or wrong value scanf("%d", &age); // Correct! |
C. Array out-of-bounds access
|
0 1 2 3 4 5 6 7 |
int arr[5]; arr[5] = 100; // Wrong! arr[5] is out of bounds |
D. Using = instead of == in conditions
|
0 1 2 3 4 5 6 7 |
if (age = 18) // Wrong! Assignment, always true if (age == 18) // Correct! |
E. Not freeing allocated memory → Memory leak
|
0 1 2 3 4 5 6 7 8 |
int *p = malloc(100 * sizeof(int)); // ... use p ... // Forgot free(p); → memory leak |
F. Dangling pointer
|
0 1 2 3 4 5 6 7 8 |
int *p = malloc(...); free(p); *p = 10; // Wrong! Using after free → undefined behavior |
G. Not checking return value of malloc/calloc
|
0 1 2 3 4 5 6 7 8 9 10 |
int *p = malloc(100000000 * sizeof(int)); if (p == NULL) { printf("Memory allocation failed!\n"); exit(1); } |
3. Debugging Techniques
A. Print debugging (most simple & effective)
|
0 1 2 3 4 5 6 |
printf("Value of x before loop: %d\n", x); |
B. Use a debugger (gdb – best tool)
- Compile with debug info:
Bash0123456gcc -g program.c -o program
- Run gdb:
Bash0123456gdb ./program
- Common gdb commands:
- break main → set breakpoint at main
- run → start program
- next (n) → step over
- step (s) → step into function
- print x → see value of x
- continue (c) → continue until next breakpoint
C. Use assertions
|
0 1 2 3 4 5 6 7 8 |
#include <assert.h> assert(age > 0); // Program stops if age <= 0 |
D. Use valgrind for memory issues
|
0 1 2 3 4 5 6 7 |
gcc -g program.c -o program valgrind --leak-check=full ./program |
Valgrind shows:
- Memory leaks
- Invalid reads/writes
- Use of uninitialized values
E. Compile with warnings
|
0 1 2 3 4 5 6 |
gcc -Wall -Wextra -Werror program.c -o program |
Fix every warning – they are hints of future bugs!
4. Memory Management Tips (Very Important in C!)
A. Always initialize pointers
|
0 1 2 3 4 5 6 7 |
int *p = NULL; // Good int *p; // Bad – dangling or garbage |
B. Check every malloc/calloc/realloc
|
0 1 2 3 4 5 6 7 8 9 |
if (p == NULL) { printf("Out of memory!\n"); exit(1); } |
C. Free exactly what you allocated
- One free() per malloc()
- Don’t free twice
- Don’t free stack variables (int x; free(&x); → crash)
D. Use tools to detect leaks
- Valgrind (Linux)
- Dr. Memory (Windows)
- Xcode Instruments (macOS)
E. Set pointer to NULL after free
|
0 1 2 3 4 5 6 7 |
free(p); p = NULL; |
F. Avoid global variables (unless really needed) – hard to track memory
Today’s Homework – Practice Best Practices
- Take any old program (like student management) and:
- Add meaningful comments
- Use consistent indentation
- Use meaningful variable names
- Add checks for malloc()
- Compile with -Wall -Wextra
- Write a program that allocates memory dynamically for student records, takes input, and frees memory properly.
- Intentionally create a memory leak (forget free()) and run valgrind to see the leak report.
- Write a small program with a bug (like array out-of-bounds or wrong scanf) and use print debugging and gdb to find and fix it.
Congratulations! You have now completed a complete beginner-to-intermediate C programming course! 🎉
Next, we can start Mini Projects to practice everything:
- Student Management System (with file handling)
- Simple Calculator
- Tic-Tac-Toe Game
- Phone Book (file-based)
- Quiz Game
- Text File Analyzer
