This complete C programming tutorial covers 102 topics — from syntax and control flow to pointers, memory, files, data structures, algorithms, and a final C application project.
Course roadmap
- Introduction to C Programming
- What is C?
- Features of C
- History of C
- C vs C++
- Installing a C Compiler
- Setting Up VS Code for C
- First C Program
- C Program Structure
- Compilation and Execution in C
- C Syntax
- Comments in C
- Variables and Constants in C
- Data Types in C
- Keywords and Identifiers in C
- Input and Output in C
- printf() and scanf() in C
- Format Specifiers in C
- Operators in C
- Arithmetic Operators in C
- Relational Operators in C
- Logical Operators in C
- Assignment Operators in C
- Bitwise Operators in C
- Increment and Decrement Operators in C
- Conditional Operator in C
- Conditional Statements in C
- if Statement in C
- if-else Statement in C
- Nested if in C
- else-if Ladder in C
- switch Statement in C
- Loops in C
- for Loop in C
- while Loop in C
- do-while Loop in C
- break and continue in C
- goto Statement in C
- Functions in C
- Function Declaration in C
- Function Definition in C
- Function Arguments in C
- Return Values in C
- Recursion in C
- Arrays in C
- One-Dimensional Arrays in C
- Multidimensional Arrays in C
- Strings in C
- String Functions in C
- Pointers in C
- Pointer Variables in C
- Pointer Arithmetic in C
- Pointers and Arrays in C
- Pointers and Functions in C
- Double Pointers in C
- Structures in C
- Nested Structures in C
- Arrays of Structures in C
- Pointers to Structures in C
- Unions in C
- Enumerations in C
- typedef in C
- Dynamic Memory Allocation in C
- malloc() in C
- calloc() in C
- realloc() in C
- free() in C
- Storage Classes in C
- auto Storage Class in C
- static in C
- extern in C
- register Storage Class in C
- File Handling in C
- Opening and Closing Files in C
- Reading and Writing Files in C
- Text Files in C
- Binary Files in C
- Preprocessor Directives in C
- #include in C
- #define in C
- Macros in C
- Conditional Compilation in C
- Header Files in C
- Command-Line Arguments in C
- Error Handling in C
- Memory Management in C
- Data Structures in C
- Linked List in C
- Stack in C
- Queue in C
- Searching Algorithms in C
- Sorting Algorithms in C
- Bubble Sort in C
- Selection Sort in C
- Insertion Sort in C
- Recursion-Based Algorithms in C
- C Debugging
- C Coding Best Practices
- C Interview Questions
- C Programming Practice Problems
- Real-World C Project
- Final Project – Complete C Application
1. Introduction to C Programming
C is a foundational systems language used in operating systems, embedded software, and performance-critical tools. This series covers language basics, memory, structures, files, algorithms, and a complete C application project.
- Install a C compiler and write Hello World.
- Learn pointers, arrays, and structs.
- Build the final C application project.
Learning path
Setup + first program
Types + control flow + functions
Arrays + strings + pointers
Structs + memory + files
DS/algorithms + best practices
Final C application
2. What is C?
C gives fine-grained control over memory and maps efficiently to machine instructions, which is why so many runtimes and OSes are written in it.
C at a glance
Compiled language
Manual memory control
Portable standard library
Foundation for many languages
3. Features of C
Key features include a small core language, powerful pointers, and a standard library for I/O and strings.
Feature list
Fast compiled code
Pointers & manual memory
Modular functions
Rich operators
Standard library (stdio, stdlib, string…)
4. History of C
Designed by Dennis Ritchie in the early 1970s for Unix, C standardized through ANSI C and later ISO revisions (C99, C11, C17, C23).
Timeline idea
Early 1970s → C created
ANSI C (C89/C90)
C99 / C11 / C17 / C23
Influence on C++/Java/C#/many others
5. C vs C++
C is procedural with manual control; C++ adds classes, templates, and a larger standard library — choose based on project needs.
Quick compare
C → procedural, simpler core
C++ → multi-paradigm OOP + generics
Both → compiled, performant
Interop possible carefully
6. Installing a C Compiler
On Windows, MinGW-w64 / MSYS2 / Visual Studio Build Tools are common options.
- Install GCC/Clang/MSVC toolchain.
- Add compiler to PATH.
- Verify with –version.
Verify compiler
gcc --version
# or
clang --version
7. Setting Up VS Code for C
Use a simple compile task (`gcc file.c -o file`) and the integrated terminal.
Compile tip
gcc main.c -Wall -Wextra -o main
./main
8. First C Program
Confirm your toolchain works before learning language details.
- Create main.c.
- Compile with gcc.
- Run the executable.
Hello World
#include <stdio.h>
int main(void) {
printf("Hello, C!n");
return 0;
}
9. C Program Structure
Typical flow: includes → declarations → main → return status.
Structure
#include headers
global declarations (sparingly)
int main(void) { ... }
helper functions
10. Compilation and Execution in C
Object files link with libraries into an executable.
Stages
Preprocess (#include/#define)
Compile to assembly/object
Link libraries
Run executable
11. C Syntax
C is case-sensitive; blocks use `{ }`.
Syntax tip
int x = 10;
if (x > 0) {
printf("positiven");
}
12. Comments in C
Explain why, not what — keep comments accurate.
Comments
// Single line
/* Multi-line
comment */
13. Variables and Constants in C
Initialize variables before reading them — uninitialized locals are dangerous.
Variables
int count = 0;
const double PI = 3.14159;
14. Data Types in C
Sizes can vary by platform — check limits.h when precision matters.
Common types
char, int, float, double
short / long / long long
signed / unsigned
size_t for sizes
15. Keywords and Identifiers in C
Don’t use keywords as names; prefer descriptive snake_case or project style.
Identifier tip
Letters, digits, underscore
Cannot start with digit
Case-sensitive
Avoid reserved keywords
16. Input and Output in C
Always check input results in real programs.
I/O idea
printf → output
scanf → input (careful)
fgets → safer line input
17. printf() and scanf() in C
scanf with %s is overflow-prone — prefer width limits or fgets.
printf/scanf
int age;
printf("Age: ");
if (scanf("%d", &age) == 1) {
printf("You are %dn", age);
}
18. Format Specifiers in C
Mismatched specifiers cause undefined behavior.
Specifiers
%d / %i → int
%u → unsigned
%f / %lf → float/double (printf/scanf differ)
%c → char
%s → string
%p → pointer
19. Operators in C
Know precedence and associativity; use parentheses for clarity.
Operator groups
Arithmetic
Relational
Logical
Bitwise
Assignment
Ternary ?:
20. Arithmetic Operators in C
Integer division truncates; watch divide-by-zero.
Arithmetic
int a = 10, b = 3;
int q = a / b; /* 3 */
int r = a % b; /* 1 */
21. Relational Operators in C
Result is 1 (true) or 0 (false) in C.
Relational
if (x >= 0 && x <= 100) {
/* in range */
}
22. Logical Operators in C
Logical operators short-circuit.
Logical
if (ptr != NULL && *ptr > 0) {
/* safe check */
}
23. Assignment Operators in C
Don’t confuse = (assign) with == (compare).
Assignment
int n = 5;
n += 2; /* 7 */
24. Bitwise Operators in C
Common in flags, protocols, and low-level code.
Bitwise
unsigned flags = 0;
flags |= 1u << 3; /* set bit 3 */
flags &= ~(1u << 3); /* clear bit 3 */
25. Increment and Decrement Operators in C
Prefer `n += 1` in complex expressions for clarity.
Inc/Dec
int i = 0;
++i; /* 1 */
i++; /* 2 */
26. Conditional Operator in C
Keep ternaries simple and readable.
Ternary
int abs_x = (x < 0) ? -x : x;
27. Conditional Statements in C
Prefer clear braces and early returns in larger functions.
Branching tools
if / else if / else
nested if
switch
28. if Statement in C
Non-zero is true in C.
if
if (score >= 50) {
printf("Passn");
}
29. if-else Statement in C
Always brace multi-line bodies; be careful with dangling else.
if-else
if (n % 2 == 0) {
printf("evenn");
} else {
printf("oddn");
}
30. Nested if in C
Deep nesting hurts readability — refactor when possible.
Nested if tip
Keep depth shallow
Use else-if ladders
Extract helper functions
31. else-if Ladder in C
Order conditions from most specific to most general.
else-if
if (temp >= 30) {
puts("Hot");
} else if (temp >= 20) {
puts("Warm");
} else {
puts("Cool");
}
32. switch Statement in C
Don’t forget break unless fall-through is intentional and commented.
switch
switch (op) {
case '+':
result = a + b;
break;
default:
puts("unknown");
}
33. Loops in C
Ensure loop conditions eventually end.
Loop choices
for → known iterations
while → condition-driven
do-while → run at least once
34. for Loop in C
Classic for counting and array traversal.
for
for (int i = 0; i < n; i++) {
printf("%dn", i);
}
35. while Loop in C
Check inputs and sentinel values carefully.
while
int n = 3;
while (n > 0) {
printf("%dn", n);
n--;
}
36. do-while Loop in C
Useful for menu loops.
do-while
int choice;
do {
printf("1) Run 0) Quitn");
scanf("%d", &choice);
} while (choice != 0);
37. break and continue in C
Use sparingly for clarity.
break/continue
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) continue;
if (i > 7) break;
printf("%dn", i);
}
38. goto Statement in C
Rare legitimate uses include multi-level error cleanup in C; prefer structured control flow.
goto tip
Avoid for normal logic
Sometimes used for centralized cleanup
Prefer functions + early returns
39. Functions in C
Keep functions focused; declare prototypes in headers when sharing.
Function
int add(int a, int b) {
return a + b;
}
40. Function Declaration in C
Headers typically hold declarations; .c files hold definitions.
Prototype
int add(int a, int b);
41. Function Definition in C
Match declaration and definition exactly.
Definition
int add(int a, int b) {
return a + b;
}
42. Function Arguments in C
Arrays decay to pointers when passed to functions.
Pass by value tip
void incr(int *n) {
(*n)++;
}
43. Return Values in C
main should return an int status (0 success by convention).
Return
double square(double x) {
return x * x;
}
44. Recursion in C
Always define a base case; watch stack depth.
Factorial
long factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
45. Arrays in C
Array size is not carried at runtime — pass length explicitly.
Array
int scores[5] = {90, 85, 88, 92, 80};
46. One-Dimensional Arrays in C
Out-of-bounds access is undefined behavior.
1D array loop
for (size_t i = 0; i < 5; i++) {
printf("%dn", scores[i]);
}
47. Multidimensional Arrays in C
Memory is contiguous row-major in C.
2D array
int grid[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
48. Strings in C
Always reserve space for the “ terminator.
String
char name[32] = "Asha";
49. String Functions in C
Prefer bounded functions and explicit sizes to reduce overflows.
string.h tip
#include <string.h>
size_t n = strlen(name);
if (strcmp(name, "Asha") == 0) {
puts("match");
}
50. Pointers in C
Pointers are central to C arrays, strings, and dynamic memory.
Pointer basics
int x = 10;
int *p = &x;
printf("%dn", *p);
51. Pointer Variables in C
NULL-initialize when appropriate; never dereference invalid pointers.
Pointer var
int *p = NULL;
p = &x;
52. Pointer Arithmetic in C
Pointer arithmetic is only meaningful within the same array object.
Pointer arithmetic
int a[3] = {10, 20, 30};
int *p = a;
printf("%dn", *(p + 1)); /* 20 */
53. Pointers and Arrays in C
`a[i]` is equivalent to `*(a + i)`.
Equivalence
a[i] == *(a + i);
54. Pointers and Functions in C
Document ownership: who allocates and who frees.
Out parameter
void fill(int *out) {
*out = 42;
}
55. Double Pointers in C
Common in functions that must change a caller’s pointer value.
Double pointer idea
void alloc_int(int **pp) {
*pp = malloc(sizeof(int));
if (*pp) **pp = 7;
}
56. Structures in C
Structs model records like Student, Point, or Order.
Struct
struct Point {
int x;
int y;
};
struct Point p = {3, 4};
57. Nested Structures in C
Keep nesting shallow for readability.
Nested struct
struct Player {
char name[32];
struct Point position;
};
58. Arrays of Structures in C
Pass length with the array for safe iteration.
Struct array
struct Point path[10];
path[0].x = 1;
path[0].y = 2;
59. Pointers to Structures in C
`p->x` is `(*p).x`.
Struct pointer
struct Point p = {1, 2};
struct Point *sp = &p;
printf("%dn", sp->x);
60. Unions in C
Only one member is active at a time — track the active type yourself.
Union tip
Overlapping storage
Useful for variants/protocol payloads
Pair with an enum tag
61. Enumerations in C
Prefer enums for states and options instead of magic numbers.
Enum
enum Status { STATUS_OK = 0, STATUS_ERR = 1 };
enum Status s = STATUS_OK;
62. typedef in C
Common for struct tags and function pointer types.
typedef
typedef struct Point {
int x;
int y;
} Point;
Point p = {0, 0};
63. Dynamic Memory Allocation in C
Every successful malloc/calloc/realloc needs a matching free path.
Heap checklist
Allocate
Check NULL
Use
Free
Set pointer NULL after free (good habit)
64. malloc() in C
Always check for NULL on failure.
malloc
int *a = malloc(10 * sizeof *a);
if (!a) {
perror("malloc");
return 1;
}
free(a);
65. calloc() in C
Helpful when you need clean buffers.
calloc
int *a = calloc(10, sizeof *a);
66. realloc() in C
Use a temporary pointer — realloc can fail and return NULL without freeing old memory.
realloc safe pattern
int *tmp = realloc(a, new_count * sizeof *a);
if (!tmp) {
/* a still valid */
return -1;
}
a = tmp;
67. free() in C
Never use memory after free; never free twice.
free
free(a);
a = NULL;
68. Storage Classes in C
Understand scope vs lifetime vs linkage.
Storage classes
auto (default locals)
static
extern
register (historical hint)
69. auto Storage Class in C
In modern C, you usually omit auto.
auto tip
Default for block-scope vars
Automatic storage duration
Rarely written explicitly today
70. static in C
static locals keep values between calls.
static local
void tick(void) {
static int n = 0;
n++;
printf("%dn", n);
}
71. extern in C
Define once, declare many times via headers.
extern tip
extern int count; /* declaration */
int count = 0; /* definition in one .c file */
72. register Storage Class in C
Modern compilers ignore most register hints; don’t take addresses of register vars (historically).
register tip
Historical optimization hint
Compilers optimize better today
Rarely useful in modern C
73. File Handling in C
Always check open success and close files.
File checklist
fopen
check NULL
read/write
fclose
74. Opening and Closing Files in C
Modes include "r", "w", "a", and binary variants like "rb".
fopen/fclose
FILE *fp = fopen("data.txt", "r");
if (!fp) {
perror("fopen");
return 1;
}
fclose(fp);
75. Reading and Writing Files in C
Prefer fgets over gets (gets is removed/unsafe).
fgets
char line[256];
while (fgets(line, sizeof line, fp)) {
fputs(line, stdout);
}
76. Text Files in C
Be mindful of newline differences across platforms.
Text file tip
"r" / "w" / "a" modes
fgets for lines
fprintf for formatted output
77. Binary Files in C
Struct padding/endianness make portable binary formats tricky.
Binary tip
FILE *fp = fopen("data.bin", "wb");
fwrite(&item, sizeof item, 1, fp);
78. Preprocessor Directives in C
Prefer functions/inline/enums over complex macros when possible.
Preprocessor map
#include
#define macros
#if / #ifdef
#include guards
79. #include in C
Use include guards or #pragma once in headers.
Include
#include <stdio.h>
#include "point.h"
80. #define in C
Parenthesize macro args and expressions.
Define
#define MAX_SIZE 100
#define SQR(x) ((x) * (x))
81. Macros in C
Side effects in macro args are a classic pitfall (`SQR(i++)`).
Macro caution
Parenthesize fully
Avoid multi-eval side effects
Prefer inline functions (C99+) when suitable
82. Conditional Compilation in C
Useful for platform-specific code and feature flags.
ifdef
#ifdef DEBUG
printf("debug moden");
#endif
83. Header Files in C
Put declarations in headers, definitions in .c files (except static inline).
Include guard
#ifndef POINT_H
#define POINT_H
typedef struct Point { int x, y; } Point;
#endif
84. Command-Line Arguments in C
argv[0] is the program name; validate argc before using argv[i].
argc/argv
int main(int argc, char *argv[]) {
if (argc < 2) {
printf("Usage: %s <file>n", argv[0]);
return 1;
}
printf("File: %sn", argv[1]);
return 0;
}
85. Error Handling in C
Check every allocation and I/O operation that can fail.
Error pattern
FILE *fp = fopen(path, "r");
if (!fp) {
perror("fopen");
return 1;
}
86. Memory Management in C
Leaks, double-frees, and use-after-free are top C bugs — design ownership rules.
Memory rules
Who allocates?
Who frees?
How long is pointer valid?
Check NULL
Tools: ASan/Valgrind
87. Data Structures in C
Arrays, linked lists, stacks, and queues build algorithmic fluency.
DS map
Array
Linked list
Stack
Queue
Trees/hash (advanced)
88. Linked List in C
Handle empty-list edge cases and free all nodes.
Node sketch
typedef struct Node {
int value;
struct Node *next;
} Node;
89. Stack in C
Define push/pop/peek and overflow/underflow behavior.
Stack ops
push
pop
peek
is_empty / is_full
90. Queue in C
Circular buffers avoid costly shifts.
Queue ops
enqueue
dequeue
front
is_empty / is_full
91. Searching Algorithms in C
Binary search needs a sorted array.
Linear search idea
int find(const int *a, int n, int key) {
for (int i = 0; i < n; i++)
if (a[i] == key) return i;
return -1;
}
92. Sorting Algorithms in C
For production, prefer battle-tested library sorts unless learning/implementing.
Sort map
Bubble / Selection / Insertion (learning)
qsort (libc)
Know O-notation trade-offs
93. Bubble Sort in C
Good teaching algorithm — rarely best in practice.
Bubble tip
Adjacent swaps
Early-exit flag optimization
O(n²) typical
94. Selection Sort in C
Simple but O(n²); minimizes swaps compared to bubble.
Selection tip
Find min in unsorted region
Swap into place
O(n²) comparisons
95. Insertion Sort in C
Efficient for nearly sorted small arrays.
Insertion tip
Good for small/nearly sorted data
Stable
O(n²) worst case
96. Recursion-Based Algorithms in C
Convert to iterative forms when stack depth is a concern.
Recursion algo tip
Base case first
Progress toward base
Mind stack usage
Memoize when overlapping subproblems
97. C Debugging
Compile with `-Wall -Wextra -g` and fix warnings early.
Debug toolkit
gcc -Wall -Wextra -g
gdb / lldb
AddressSanitizer
Valgrind (where available)
printf bisect carefully
98. C Coding Best Practices
Initialize variables, check returns, bound buffers, and keep functions small.
Best practices
Enable warnings
Check all errors
No buffer overflows
Clear pointer ownership
Const-correctness
Small testable functions
99. C Interview Questions
Be ready for undefined behavior, stack vs heap, and string pitfalls.
Sample Q&A
Q: Array vs pointer?
A: Arrays are not pointers, but decay to pointers in most expressions.
Q: malloc vs calloc?
A: calloc zero-initializes and takes count*size.
Q: What is UB?
A: Undefined behavior — e.g., out-of-bounds access.
100. C Programming Practice Problems
Solve, then refactor for clarity and safety.
Practice set
Sum/average array
Reverse string in place
Frequency count
Simple linked list CRUD
Word count in a file
Student records struct + file
101. Real-World C Project
Include Makefile, README, and sample inputs.
Project ideas
CLI todo file manager
CSV summarizer
Simple contact book
Log file analyzer
Mini key-value store on disk
102. Final Project – Complete C Application
Create a polished CLI app (e.g., student record system or inventory manager) with structs, file persistence, dynamic memory, input validation, a Makefile, and README. Handle errors and free all allocations.
- Design features and data model.
- Implement modules and persistence.
- Add validation and cleanup.
- Document build/run steps and test flows.
Final project scope
1. App idea + features list
2. Modular .h/.c design
3. Struct-based records
4. Dynamic array or linked list
5. File save/load
6. Menu-driven CLI
7. Input validation + error handling
8. Makefile + README
9. Memory clean on exit
Suggested layout
src/main.c
src/app.c / app.h
src/storage.c / storage.h
Makefile
README.md
sample data file
Conclusion
You now have a full C path: language fundamentals, memory mastery, modular design, and algorithmic practice. Finish the final C application project to turn the lessons into a portfolio-ready program.