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 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.
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 would paste its contents twice, causing a "redefinition" compile error. 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
int add(int a, int b);
#endif
// or, more concisely (widely supported, though not part of the official standard):
// #pragma once