Der Grund ist, dass C die Funktionen sequentiell abläuft. Beispiel: Stell dir vor, du hast zwei Funktionen:

Code:
void a()
{
 b();
}

void b()
{
 // tu was
}
In der Funktion a() wird b() aufgerufen. Der Compiler weiß aber noch nichts von b(), da diese Funktion erst nach a() definiert wird. Folglich hat er auch noch keine Sprungmarke.
Mit der Header-Datei lässt sich dieses Problem nun beheben. Die Header-Datei reserviert nun für jede Funktion Sprungmarken, sodass nun a() weiß, wohin es springen muss, wenn b() aufgerufen wird.

Dieses Verhalten kannst du auch nachvollziehen, da die Funktionen nicht unbedingt in der Header-Datei stehen müssen. Du kannst mein Beispiel übernehmen. Erst wenn du b() zuerst definierst, kann a() auch b() aufrufen.
Also anstatt den oberen Code musst du dann:

Code:
void b()
{
 // tu was
}

void a()
{
 b();
}
schreiben.

Bei aktuellen Sprachen ist die Header-Datei nicht mehr nötig, weil der Code zuerst analysiert wird, und dann für jede Methode/Funktion implizit schon eine Sprungmarke definiert wird. Aktuelle Compiler bauen also quasi implizit die Header-Datei selbst.