Three-File Format
main.c + lib.c + lib.h, the one-definition rule, and why programs split cleanly or painfully
In a nutshell
In Java, when Main.java needed Car, the compiler found Car.class on the classpath and worked out the rest. In C you do that work by hand. A program with more than one source file uses the three-file pattern: main.c (drives the program), lib.c (holds function definitions), lib.h (holds function prototypes, #define constants, and extern declarations of shared data). Every .c file that needs a function declared in lib.h writes #include "lib.h", and the linker stitches the object files together at build time.
The one-definition rule is the non-negotiable: every function and every variable has exactly one definition in the whole program, even though it can be declared (through #include) as many times as needed. extern is how you declare without defining. Include guards (#ifndef/#define/#endif) prevent a header from being pasted into the same translation unit twice.
Why it matters
Every lab from Lab 6 onward has more than one .c file. Every real-world C project (the Linux kernel, git, sqlite, curl) uses exactly this pattern at massive scale. A program that is organized well splits naturally; one that is organized poorly produces multiple-definition linker errors, circular includes, and changes that cascade across the whole source tree. This is also where make pays for itself: with the three-file pattern, make can rebuild only the files whose sources (or header dependencies) actually changed.
Key takeaways
.hfiles declare..cfiles define. Prototypes,#define,typedef,structlayouts (when shared), andexterndeclarations go in.h. Function bodies and variable definitions with storage go in exactly one.cfile.- One-definition rule. For any name, many declarations are fine; exactly one definition is required.
externdeclares; it does not define.extern const double FLAT_R;in a header,const double FLAT_R = 5.00;in exactly one.cfile.- Include guards prevent double-inclusion within one translation unit. They do not protect against accidentally putting a definition in a header (which creates multiple definitions across translation units, not within them).
- Use
"..."for your own headers,<...>for system headers. Different preprocessor search rules. makeis a build tool, not a compile tool. It runsgcccommands you tell it to, and only when their inputs changed.
Lessons in this topic
| Lesson | What it covers |
|---|---|
Three-File Model & extern |
Interface vs implementation, include guards with mechanism, declarations vs definitions, extern with a worked example, Makefile basics, CLI args |
Planned for week 6 (coming):
makeinternals:.PHONY, pattern rules, dependency tracking with-MMDstatickeyword (its three different meanings in C)- Header hygiene: forward declarations vs full definitions
Practice and deep dives
Practice this topic: Headers & Makefiles drill, or browse the practice gallery.
What comes next
Week 6 opens with Structs & typedef. Once you can organize code across files and bundle related data into struct types, you have the basic toolkit for every real C program.