Phase 9 — Projects + Interview + Real-World C
Phase 9 is where we stop learning C as isolated concepts and start using it like a real C programmer.
The focus is:
BUILD → DEBUG → REVIEW → BREAK → FIX → INTERVIEW
Module 1 — CLI Programs
Chapter 1 — Command-Line Arguments
Question
The program receives arguments from the command line.
#include <stdio.h>
int main(int argc, char *argv[]) {
// Print how many command-line arguments were supplied.
printf("Count: %d\n", argc);
// Print the first two user-supplied arguments if they exist.
if (argc > 1)
printf("First: %s\n", argv[1]);
if (argc > 2)
printf("Second: %s\n", argv[2]);
return 0;
}Suppose we run:
./app hello CWhat is the output?
Answer
Count: 3
First: hello
Second: CStep-by-step explanation
argc means argument count.
argv means argument vector—an array of strings.
The command:
./app hello Ccontains:
argv[0] = "./app"
argv[1] = "hello"
argv[2] = "C"Therefore:
argc = 3How to read it
Read:
int main(int argc, char *argv[])as:
"The program receives a number of arguments and an array containing those arguments."
Key takeaway
Command-line arguments let a C program receive input when it starts.
Module 2 — File-Based Applications
Chapter 2 — File Persistence
A real application often needs to preserve data after the program exits.
Question
#include <stdio.h>
int main(void) {
// Open a file for writing.
FILE *file = fopen("data.txt", "w");
// Make sure the file opened successfully.
if (file == NULL)
return 1;
// Write data into the file.
fprintf(file, "Alice 95\n");
fprintf(file, "Bob 87\n");
// Close the file.
fclose(file);
return 0;
}After successful execution, what happens?
Answer
A file named:
data.txtis created containing:
Alice 95
Bob 87Step-by-step
FILE *filestores a handle representing the opened file.
fopen("data.txt", "w")opens it in write mode.
fprintf(file, ...)writes formatted text.
fclose(file)closes the file and releases the associated resource.
Beginner trap
"w" can overwrite an existing file.
For adding to the end, use:
"a"Key takeaway
Files allow program data to survive after the process terminates.
Module 3 — Student/Contact Management System
Chapter 3 — Structures + Arrays + Functions
This is your first realistic mini-application.
Question
#include <stdio.h>
struct Student {
int id;
char name[30];
float marks;
};
void print_student(struct Student s) {
// Display one student's information.
printf("%d | %s | %.1f\n", s.id, s.name, s.marks);
}
int main(void) {
// Store multiple students in an array.
struct Student students[2] = {
{1, "Alice", 91.5},
{2, "Bob", 84.0}
};
// Print every student.
for (int i = 0; i < 2; i++)
print_student(students[i]);
return 0;
}What is the output?
Answer
1 | Alice | 91.5
2 | Bob | 84.0What this demonstrates
A real application combines:
struct
↓
array
↓
function
↓
loop
↓
formatted outputThis is much closer to real programming than isolated syntax exercises.
Key takeaway
Real C programs are compositions of the fundamentals you've already learned.
Module 4 — Dynamic Data Structures
Chapter 4 — Linked List
Question
#include <stdio.h>
#include <stdlib.h>
struct Node {
int value;
struct Node *next;
};
int main(void) {
// Allocate the first node dynamically.
struct Node *a = malloc(sizeof *a);
// Allocate the second node dynamically.
struct Node *b = malloc(sizeof *b);
// Store values.
a->value = 10;
b->value = 20;
// Connect the nodes.
a->next = b;
b->next = NULL;
// Walk through the list.
for (struct Node *p = a; p != NULL; p = p->next)
printf("%d ", p->value);
// Release both nodes.
free(b);
free(a);
return 0;
}What is printed?
Answer
10 20Step-by-step
Memory conceptually looks like:
a
↓
+-------+-------+
| 10 | ●---|----+
+-------+-------+ |
↓
+-------+-------+
| 20 | NULL |
+-------+-------+
ba->next = b means:
The first node points to the second node.
The loop:
p = p->nextmoves through the list.
Key takeaway
A linked list is dynamically allocated nodes connected through pointers.
Module 5 — Mini Database-Style Application
Chapter 5 — CRUD Thinking
A practical application usually performs:
Create
Read
Update
DeleteThese are commonly called CRUD operations.
Question
#include <stdio.h>
#include <string.h>
struct User {
int id;
char name[20];
};
int main(void) {
struct User users[3] = {
{1, "Alice"},
{2, "Bob"},
{3, "Carol"}
};
// Update Bob's name.
strcpy(users[1].name, "Robert");
// Delete conceptually by shifting later records left.
users[1] = users[2];
// Display remaining logical records.
for (int i = 0; i < 2; i++)
printf("%d %s\n", users[i].id, users[i].name);
return 0;
}What is printed?
Answer
1 Alice
3 CarolImportant insight
C doesn't automatically provide:
database.delete()You must design the data representation and operations yourself.
This is why C is excellent for learning how abstractions actually work.
Key takeaway
In C, you build the machinery behind higher-level abstractions yourself.
Module 6 — Multi-File Project
Chapter 6 — .h + .c
A real C project shouldn't necessarily put everything into one file.
Typical structure:
project/
├── main.c
├── math.c
└── math.hQuestion
math.h:
#ifndef MATH_H
#define MATH_H
int add(int a, int b);
#endifmath.c:
#include "math.h"
int add(int a, int b) {
return a + b;
}main.c:
#include <stdio.h>
#include "math.h"
int main(void) {
// Call a function implemented in another source file.
printf("%d\n", add(10, 20));
return 0;
}What is printed?
Answer
30The important distinction
Header:
int add(int a, int b);is a declaration.
Implementation:
int add(int a, int b) {
return a + b;
}is the definition.
Key takeaway
Headers describe interfaces; .c files contain implementations.
Module 7 — Reusable C Library
Chapter 7 — Designing an API
Suppose we want a small stack library.
Question
#include <stdio.h>
struct Stack {
int values[3];
int top;
};
void push(struct Stack *s, int value) {
// Add a value at the top.
if (s->top < 3)
s->values[s->top++] = value;
}
int pop(struct Stack *s) {
// Remove and return the top value.
if (s->top == 0)
return -1;
return s->values[--s->top];
}
int main(void) {
struct Stack s = {0};
push(&s, 10);
push(&s, 20);
printf("%d\n", pop(&s));
printf("%d\n", pop(&s));
return 0;
}Output?
Answer
20
10Why pass &s?
Because push() and pop() need to modify the original stack.
push(&s, 10);passes its address.
Inside:
struct Stack *sis a pointer to the original object.
Key takeaway
A C API is a carefully designed set of functions and types through which other code interacts with your component.
Module 8 — Memory-Intensive Programming
Chapter 8 — Dynamic Allocation
Question
#include <stdio.h>
#include <stdlib.h>
int main(void) {
// Allocate space for five integers.
int *numbers = malloc(5 * sizeof *numbers);
if (numbers == NULL)
return 1;
// Initialize the allocated array.
for (int i = 0; i < 5; i++)
numbers[i] = i * 10;
// Print the values.
for (int i = 0; i < 5; i++)
printf("%d ", numbers[i]);
// Release the allocated memory.
free(numbers);
return 0;
}Output?
Answer
0 10 20 30 40Critical concept
This memory:
malloc(...)belongs to your program until you release it.
Therefore:
free(numbers);is essential.
Key takeaway
Every successful dynamic allocation needs a deliberate lifetime and eventual release.
Module 9 — Debugging Projects
Chapter 9 — Finding a Memory Bug
Question
What's wrong?
#include <stdio.h>
#include <stdlib.h>
int main(void) {
// Allocate one integer.
int *p = malloc(sizeof *p);
if (p == NULL)
return 1;
*p = 42;
// Release the memory.
free(p);
// BUG: p no longer points to valid allocated storage.
printf("%d\n", *p);
return 0;
}Answer
The program has use-after-free.
After:
free(p);the allocation is no longer valid.
Therefore:
*pis undefined behavior.
Correct approach
If the value is needed first:
printf("%d\n", *p);
free(p);Key takeaway
free() ends the lifetime of the allocated object; the pointer does not magically become safe.
Module 10 — Output Prediction
Chapter 10 — Pointer Interview Question
Question
#include <stdio.h>
int main(void) {
int x = 10;
// p stores the address of x.
int *p = &x;
// q stores the address of p.
int **q = &p;
// Modify x through the pointer-to-pointer chain.
**q = 50;
printf("%d %d %d\n", x, *p, **q);
return 0;
}Output?
Answer
50 50 50Why?
Think:
q
↓
p
↓
xTherefore:
**qeventually reaches x.
Changing:
**q = 50;changes the original variable.
Key takeaway
A pointer-to-pointer is simply another level of indirection.
Module 11 — C Interview Problems
Chapter 11 — Array vs Pointer
Question
#include <stdio.h>
void change(int *p) {
// Modify the original value.
*p = 100;
}
int main(void) {
int x = 10;
change(&x);
printf("%d\n", x);
return 0;
}Output?
Answer
100Interview point
C uses pass-by-value.
The function receives a copy of the pointer:
pbut that pointer points to the original x.
Therefore:
*p = 100;changes x.
Key takeaway
C passes arguments by value; passing a pointer value allows a function to modify the pointed-to object.
Module 12 — Code Review
Chapter 12 — Review AI-Generated C
Question
An AI generates:
char *copy_name(const char *name) {
char buffer[20];
strcpy(buffer, name);
return buffer;
}Is this safe?
Answer
No.
There are actually two major problems.
Problem 1 — Returning a dead object
char buffer[20];is local automatic storage.
It stops existing when the function returns.
Therefore:
return buffer;returns a pointer to invalid storage.
This creates a dangling pointer.
Problem 2 — Buffer overflow
strcpy(buffer, name);doesn't know that buffer only has room for 20 bytes.
A sufficiently long name can overflow it.
Better design
One possible design is:
char *copy_name(const char *name) {
size_t length = strlen(name) + 1;
char *copy = malloc(length);
if (copy == NULL)
return NULL;
memcpy(copy, name, length);
return copy;
}Now the caller owns the returned allocation and must eventually:
free(copy);Key takeaway
Never trust generated C code merely because it compiles.
Module 13 — Security-Oriented C
Chapter 13 — Buffer Overflow
Question
#include <stdio.h>
int main(void) {
char name[8];
// Dangerous: no size limit is supplied.
scanf("%s", name);
printf("Hello %s\n", name);
return 0;
}What's dangerous?
Answer
name can hold only a limited number of characters.
But:
scanf("%s", name);can accept a much longer input.
That can write beyond the array's bounds.
This is a buffer overflow.
Safer approach
Use a bounded input strategy, for example:
fgets(name, sizeof name, stdin);Key takeaway
Every input operation must respect the size of the destination buffer.
Module 14 — Resource Leaks
Chapter 14 — Memory Isn't the Only Resource
Question
#include <stdio.h>
int main(void) {
FILE *file = fopen("data.txt", "r");
if (file == NULL)
return 1;
// Read the file...
return 0;
}What's missing?
Answer
fclose(file);The file is a resource and should be released.
Correct structure:
FILE *file = fopen("data.txt", "r");
if (file == NULL)
return 1;
/* use file */
fclose(file);Important insight
Resources include:
memory
files
sockets
locks
handles
process resourcesKey takeaway
Resource management is a core professional C skill.
Module 15 — Debugging Methodology
Chapter 15 — Don't Guess, Isolate
When a C program crashes, don't randomly change code.
Use this process:
1. Reproduce
↓
2. Minimize
↓
3. Identify exact failure
↓
4. Inspect state
↓
5. Find violated assumption
↓
6. Fix root cause
↓
7. Test againQuestion
Suppose this crashes:
int *p = NULL;
// Somewhere later:
*p = 10;What should you investigate first?
Answer
The immediate issue is:
p == NULLand therefore:
*pattempts to dereference a null pointer.
Professional mindset
Don't ask:
"How do I stop the crash?"
Ask:
"Why was
pNULL at this point?"
That distinction is extremely important.
Key takeaway
Debug the cause, not merely the symptom.
Module 16 — Testing
Chapter 16 — Test Edge Cases
Question
Consider:
int divide(int a, int b) {
return a / b;
}What cases should you test?
Answer
At minimum:
10 / 2
10 / 1
10 / -2
0 / 5
5 / 0
INT_MAX / 1
INT_MIN / -1The important case is:
5 / 0which is invalid.
Testing mindset
Don't test only:
normal inputTest:
empty input
zero
negative values
maximum values
minimum values
very large input
unexpected input
NULL
allocation failure
missing files
duplicate dataKey takeaway
Good tests attack the assumptions your code makes.
Module 17 — Build Systems
Chapter 17 — Makefile Thinking
A multi-file C project might contain:
main.c
student.c
student.hCompilation conceptually becomes:
main.c ──→ main.o ──┐
├──→ executable
student.c → student.o┘Question
If student.c changes, do you necessarily need to recompile main.c?
Answer
No.
Ideally only the affected source file is recompiled:
student.c
↓
student.o
↓
linkThis is one reason build systems such as make are useful.
Key takeaway
Build systems automate dependency-aware compilation and linking.
Module 18 — Performance
Chapter 18 — Know Where Time Goes
Question
Which is generally more expensive?
for (int i = 0; i < n; i++) {
printf("%d\n", array[i]);
}or simply:
for (int i = 0; i < n; i++) {
int x = array[i];
}Answer
The first is generally much more expensive because I/O is costly compared with ordinary memory access.
Important lesson
Don't optimize based on appearance.
Measure.
Typical workflow:
Correctness
↓
Profile
↓
Find bottleneck
↓
Optimize bottleneck
↓
Measure againKey takeaway
Performance optimization should be driven by measurements, not guesses.
Module 19 — Capstone Project
Chapter 19 — Contact Management System
Now combine everything.
Your capstone should support:
CREATE contact
READ contacts
SEARCH contact
UPDATE contact
DELETE contact
SAVE to file
LOAD from file
EXITSuggested structure:
contact-manager/
│
├── main.c
├── contact.c
├── contact.h
├── storage.c
├── storage.h
└── MakefileArchitecture:
main
│
┌───────┴────────┐
↓ ↓
contact API storage API
↓ ↓
structures file I/O
│ │
└───────┬────────┘
↓
disk fileThis project forces you to use:
structures
arrays/dynamic memory
pointers
strings
functions
multiple files
headers
file handling
error handling
searching
updating
deletion
memory management
build systems
Key takeaway
A capstone is where individual C concepts become an actual software system.
Module 20 — Interview Preparation
Chapter 20 — What You Should Be Able to Explain
At the end of Phase 9, you should be able to answer questions such as:
Fundamentals
What happens when C code is compiled?
What is the difference between declaration and definition?
What is the difference between compiler and linker?
What is an object file?
What is
sizeof?What is undefined behavior?
Pointers
What is a pointer?
What does
&xmean?What does
*pmean?What is pointer arithmetic?
What is
void *?What is a dangling pointer?
What is a NULL pointer?
What is a wild pointer?
What is
int **?What is a function pointer?
Memory
Stack vs heap?
What does
malloc()do?malloc()vscalloc()?What does
realloc()do?What happens after
free()?What is a memory leak?
What is use-after-free?
What is double free?
Strings
How are C strings represented?
What is
'\0'?Why can
strcpy()be dangerous?Why is buffer size important?
Structures
structvsunion?What does
->mean?What is
typedef?How are structures passed to functions?
Compilation
What does preprocessing do?
What does compilation do?
What does assembly do?
What does linking do?
Why do we use header files?
Why do we need include guards?
Professional C
How do you debug a segmentation fault?
How do you find a memory leak?
Why should compiler warnings be enabled?
What are sanitizers?
How do you review AI-generated C?
How do you make C code portable?
How do you handle errors?
Module 21 — AI/Vibe-Code Review
Chapter 21 — The Ultimate Skill
This is one of the most important exercises for your goal.
When AI gives you:
char *get_data(void) {
char buffer[100];
// AI says this returns the data.
return buffer;
}You should immediately ask:
Where does buffer live?
When does its lifetime end?
Who owns the returned pointer?
Can the caller safely use it?You should recognize:
local array
↓
function returns
↓
lifetime ends
↓
returned pointer becomes danglingThen challenge the AI.
Phase 9 Final Skill Test
You are not finished with C merely because you can write this:
printf("Hello World");You are approaching professional competency when you can look at unfamiliar C and mentally reason about:
SOURCE CODE
↓
preprocessing
↓
compilation
↓
assembly
↓
linking
↓
executable
↓
process
↓
┌───────┴────────┐
↓ ↓
stack heap
↓ ↓
local objects allocations
↓ ↓
pointers ─────→ memory
↓
data structures
↓
algorithms
↓
files/resources
↓
errors/UB/security
↓
debugging/testingAnd when AI generates C, your mental checklist should become:
1. Does it compile?
2. Are the compiler warnings clean?
3. Is the logic correct?
4. Are array bounds respected?
5. Are pointers valid?
6. Are lifetimes correct?
7. Who owns allocated memory?
8. Who frees it?
9. Can allocation fail?
10. Can input overflow buffers?
11. Can NULL occur?
12. Can integer overflow occur?
13. Is there undefined behavior?
14. Are files/resources closed?
15. Is the code portable?
16. Is error handling adequate?
17. Can it be tested?
18. Can it be maintained?
19. Can it be attacked?
20. Can I explain every important line?Final Phase 9 Objective
You should now be moving from:
“I know C syntax.”
to:
“I can build a C program.”
and ultimately:
“I can inspect a C program and understand what it is doing with memory, data, files, and the operating system—and I can tell when AI-generated C is wrong.”
That is the real purpose of Phase 9.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.