ein Kapitel zurück                                           ein Kapitel weiter

Wozu benötigen wir überhaupt Funktionen? Sicherlich man könnte hergehen und alles in die main() - Funktion packen. Aber nehmen wir mal an wir schreiben ein Programm zur Eingabe von 10 Messdaten. Um zu überprüfen ob die Messdaten jetzt in ihrer Toleranz sind und ob auch wirklich Zahlen, und keine Buchstaben eingegeben wurden, müssen sie jetzt in der main() - Funktionen 10x überprüfen ob der Messwert in der Toleranz ist und 10x überprüfen ob es bei der Eingabe auch wirklich um Zahlen handelt. Einfacher wäre es doch 2 Funktionen zu Schreiben. Eine überprüft die Toleranz und die Andere überprüft auf korrekte Eingabe. Sie sollten sich allgemein immer Überlegen bevor sie ein Projekt anfangen welche Funktionen sie schreiben und was diese Bewirken sollen.

Eine Funktion kennen sie bereits schon die main() - Funktion...

int main()
{
 .........
}


Jetzt wollen wir doch mal ein Funktion etwas genauer Analysieren.....

Rueckgabewert Funktionsname(Parameter1,Parameter2.....)
{
/*Anweisungsblock in der die Funktion das tut wofür wir sie Programmieren...*/
}


Als erstes hätten wir da den Rückgabewert einer Funktion. Wenn z.B. eine Funktion, an den Aufrufer der Funktion, einen Wert zurückgeben soll, z.B. eine Dezimalzahl wäre das z.B. int oder long.
Der Funktionsname ist der Name mit dem sie von der main-Funktion oder anderen Modulen bzw. Funktionen aufrufen können.
Des weiteren können sie einer Funktion Parameter übergeben die wir in der Funktion dann zum weiteren Bearbeiten verwenden könnten.
Zwischen dem Anweisungsblock steht dann was mit, falls sie Parameter übergeben, den Parametern geschehen soll. Zum Beispiel....

void addiere(int zahl1, int zahl2)
{
 printf("Die Summe beträgt %d\n",zahl1+zahl2);
}


Aufrufen bzw. Verwenden können sie diese Funktion wenn sie z.B. in der main - Funktion schreiben...

addiere(5,10);

Somit wird unsere Funktion addiere() aufgerufen und ausgeführt. Als Parameter übergeben wir der Funktion die beiden Zahlen 5 und 10. Die Funktion gibt das Ergebnis 15 aus hat aber keinen Rückgabewert (void).

Bevor wir etwas genauer dazu kommen muss ich Ihnen erst noch schnell den Bezug zwischen Variablen wie z.B. int,long... und Funktionen erklären.

/*Download:func1.c*/
#include <stdio.h>

void aendern(void)
{
int zahl=10;
}

int main()
{
int zahl = 1;

printf("%d\n",zahl);
aendern(); /*Funktionsaufruf*/
printf("%d\n",zahl);
return 0;
}

Nun zur Erklärung unserer ersten Funktion. Wenn sie das Programm ausführen geht es mit der main()-Funktion los. Das können sie sich gleich merken, egal wie viele Funktionen sie schreiben ein Programm in C beginnt zuerst mit der main()-Funktion. Wir hätten das Programm auch anders schreiben können und zwar die main()-Funktion zuerst und dann die Funktion aendern. Wenn sie es so machen müssen sie einen Prototyp angeben. Hier die andere Möglichkeit...

/*Download:func2.c*/
#include <stdio.h>

void aendern(void); /*Prototyp*/

int main()
{
int zahl = 1;

printf("%d\n",zahl);
aendern(); /*Funktionsaufruf*/
printf("%d\n",zahl);
return 0;
}

void aendern(void)
{
int zahl=10;
}

Hier müssen sie einen Prototypen angeben damit der Compiler beim Start bescheid weiß das es eine solche Funktion überhaupt gibt. Ok, soviel zur Schreibweise. Bestimmt haben sie das Programm schon getestet? Falls noch nicht geschehen dann machen sie es jetzt.

Wenn das Programm startet,wird erst der Wert 1 ausgegeben, mit dem die Variable zahl Initialisiert wurde. Dann wird die Funktion mittels....

aendern();

...aufgerufen. Jetzt wird in der Funktion eine Variable, ebenfalls mit dem Namen zahl, mit dem Wert 10 initialisiert. Das war auch schon alles was die Funktion bezweckte. Nun springt unser Programm wieder in die main()-Funktion zurück und gibt die Zahl 1 aus. Bestimmt haben sie erwartet das die letzte Ausgabe den Wert 10 hat. Nun die Erklärung ist ganz einfach. Die Variable wurde innerhalb eines Anweisungsblockes definiert und ist somit Lokal sichbar. Das heißt dieser Wert ist nur innerhalb diese Blockes, in unserem Fall innerhalb der Funktion aendern(), gültig. Jetzt wollen wir uns ansehen wie wir den Wert 10 aber tatsächlich auch ausgeben können....

/*Download:func3.c*/
#include <stdio.h>

void aendern(void)
{
int zahl=10;

printf("%d\n",zahl); /*Jetzt wird 10 ausgegeben*/
}

int main()
{
int zahl = 1;

printf("%d\n",zahl);
aendern(); /*Funktionsaufruf*/
printf("%d\n",zahl);
return 0;
}

Ein weiteres Beispiel zum Thema Lokale Variablen....

/*Download:func4.c*/
#include <stdio.h>

int main()
{
int zahl;
printf("Bitte eine Zahl eingeben : ");
scanf("%d",&zahl);
if(zahl>0)
{
int i = 5;
i=zahl*i;
printf("%d\n",i);
}
printf("%d\n",i); /*i=Unbekannt*/
return 0;
}


Wenn sie versuchen das Programm zu übersetzen wird es nicht gehen. Der Compiler wird anfangen zu meckern das er 'i' nicht kennt. Die Variable 'i' ist nur im Anweisungsblock von...

if(zahl

...gülig. Im Gegensatz zu C++ müssen in C die Variablen schon zum Beginn der Funktionen angeben.

2. Globale Variblen
Globale Variablen sind wie der Name schon sagt über das ganz Programm hin gültig. Man erkennt Diese daran, weil diese nicht in einem Anweisungsblock stehen....

/*Download:func5.c*/
#include <stdio.h>

int zahl=1; /*globale Variable i*/

void aendern(void)
{
int zahl=10;
}

int main()
{
printf("%d\n",zahl);
aendern(); /*Funktionsaufruf*/
printf("%d\n",zahl);
return 0;
}


Wie sie sehen haben wir hier die Variable 'zahl' außerhalb der main()-Funktion definiert. Das heißt nun das diese Variable im ganzen Programm für alle Funktionen "sichtbar" ist. Somit funktioniert jetzt die Funktion aendern() und ändert den Wert tatsächlich in 10 um. Nur sollten sie globale Definitionen auch vorsichtig einsetzen. Wenn sie zum Beispiel bei unserem Programm in der main()-Funktion....

int zahl=99;

...einfügen werden die beiden Ausgaben auch 99 sein. Warum? Nun es sind hier nun mal zwei Variablen mit dem Namen 'zahl' deklariert worden, die zwar den gleichen Namen haben aber im Speicher eine ganz andere Adresse. Wie schon oben gesagt benutzt eine Programm die Variable die am lokalsten ist. Bei unserem Aufruf in der Funktion aendern() wurde der Wert von 'zahl' aber tatsächlich verändert. Nämlich die Globale Variable 'zahl'. Hier das Programm als Beweis...

/*Download:func6.c*/
#include <stdio.h>

int zahl=1;

void aendern(void)
{
printf("%d\n",zahl); /*zahl=1 (globale 'zahl')*/
int zahl=10; /*nicht erlaubt in ANSI-C*/
printf("%d\n",zahl); /*zahl=10 (lokale 'zahl')*/
}

int main()
{
printf("%d\n",zahl);
aendern(); /*Funktionsaufruf*/
printf("%d\n",zahl);
return 0;
}


Diese Programm wird übrigens auf reinen C-Compilern wahrscheinlich nicht laufen, die in der Funktion aendern() die Variablendeklaration nicht zu Beginn des Anweisungsblock erfolgte.

Was ist jetzt besser Global oder Lokal?
So lokal wie möglich und so global wie nötig

Jetzt kennen sie schon Bezug zu globalen und lokalen Variablen. Jetzt benötigen wir noch etwas womit sich eine Funktion den Wert merkt um diesen Wert bei erneutem Aufruf wiederum verwenden zu können.

3. Statische Variablen
Auch hierzu erst mal ein Beispiel....

/*Download:func7.c*/
#include <stdio.h>


void dekrement(void)
{
static int zahl=1;
printf("%d\n",zahl++);
}

int main()
{
dekrement();
dekrement();
dekrement();
dekrement();
return 0;
}


Bei unserem Programm rufen wir in der main()-Funktion 4 mal die Funktion dekrement() auf. Nach unserem Wissen müsste das Programm 4 mal die eins ausgeben, denn nach jedem Funktionsaufruf wir die Variable zahl neu festgelegt. Denn nach Beendigung einer Funktion wird die Variable ja gelöscht (Sonst würde ja irgendwann der Stack überlaufen). Aber bei unserem Beispiel wird 1,2,3,4 ausgegeben. Nun das haben wir dem Wort 'static' zu Verdanken. Denn Statische Variablen verlieren bei Beendigung Ihres Bezugsrahmen nicht den Wert sondern behalten diesen bei. Sie können das Programm ja mal testweise ohne 'static' Ausführen.

ABER Statische Variablen müssen bei ihrer Definition initialisiert (einen Wert zuweisen) werden!!!!!!

Des weiteren sollten weitere Schlüsselwörter die man Variablen voranstellt (siehe static) nicht unerwähnt bleiben. Hierbei handelt es sich um die Schlüsselwörter auto, register und extern...

auto
Der Name kommt daher das sich durch voranstellen einer Variable von auto die Variable Automatisch anlegt und auch Automatisch wieder löscht ohne das sich der Programmierer darum kümmern muss. Der Bezugsrahmen von auto ist der selbe wie bei lokalen Variablen. So ist z.B. ...

int zahl=5;

...dasselbe wie.....

auto int zahl=5;

Folglich ist das Schlüsselwort auto überflüssig.

register
Wird eigentlich heute überhaupt nicht mehr benutzt. Der Bezugsrahmen ist der selbe wie bei auto und lokale Variablen. Durch voransetzen des Wortes register weisen sie den Compiler an eine Variable so lange wie möglich im Prozessorregister (CPU-Register) zu halten um dann blitzschnell darauf zugreifen zu können. Denn die Prozessorregister arbeitet wesentlich schneller als der Arbeitsspeicher. Beispielsweise für Zähler enger Schleifen. Allgemein wird davon abgeraten den ob und welche Variable der Compiler in den schnellen Prozessorregister hält entscheidet er letztlich lieber selber.

extern
....stellt eigentlich gar keine Speicherklasse da. extern benötigen wir wenn wir mehrere Module von Programmen haben und sie dann compilieren. Wir kommen noch darauf zurück wenn wir sie benötigen.

ein Kapitel zurück          nach oben           ein Kapitel weiter


© 2001,2002 Jürgen Wolf