A header file (.h) declares function prototypes, struct/type definitions, and macros meant to be shared across multiple .c source files, without containing their actual implementations. #include works via the C preprocessor, which runs before real compilation and literally replaces the #include line with the entire contents of the named file — there's no module system, namespace, or dedicated import mechanism underneath; it's pure textual substitution.
Angle brackets vs quotes
<stdio.h> searches the compiler's standard system include paths first; "myheader.h" searches the current directory (relative to the including file) first, then falls back to the system paths — the distinction matters for finding your own project's headers vs the standard library's.
#include <stdio.h> // system header: standard library
#include "mymath.h" // your own project header, in the local directoryDeclaring in a header, defining in a .c file
The header declares add()'s signature (plus a small Point type it works with) so any file including it knows how to call it correctly; the actual implementation lives in exactly one .c file, compiled separately and linked together afterward. Note the two declarations aren't equally fragile: a plain function prototype like int add(int a, int b); can legally appear more than once in a translation unit — repeating it verbatim isn't an error. A type definition like the Point struct below is different: defining the same tag/typedef twice is a genuine "conflicting types" error, which is exactly the double-inclusion risk the next section covers.
typedef struct {
int x;
int y;
} Point;
int add(int a, int b); // declaration only — no body#include "mymath.h"
int add(int a, int b) { // the actual implementation, in ONE place
return a + b;
}Include guards: preventing double-inclusion
If the same header gets #included twice in one translation unit (a common situation when several headers each include a shared one), the preprocessor pastes its contents twice. For the bare add() prototype alone that's harmless — a repeated, identical declaration compiles fine (verified: zero warnings even with -Wall -Wextra -Wpedantic). But Point's definition would genuinely be pasted twice too, and that is a real "conflicting types" compile error (verified directly: gcc rejects a struct typedef defined twice with that exact message) — headers commonly mix declarations that tolerate repetition with type/macro definitions that don't, so the safe default is to guard the whole file. An include guard — or the equivalent, more concise #pragma once — makes the second inclusion a no-op.
#ifndef MYMATH_H // classic include guard: "if MYMATH_H isn't defined yet"
#define MYMATH_H
typedef struct {
int x;
int y;
} Point;
int add(int a, int b);
#endif
// or, more concisely (widely supported, though not part of the official standard):
// #pragma once