Einführung

Funktionen werden benötigt um komplexe Programme logisch zu gliedern und in kleinere Teilprobleme zu zerlegen. Desweiteren erhöhen sie die Wiederverwendbartkeit eines Programms, da Funktionen Parameter zur Steuerung von Funktionsabläufen und Ergebnissen bereit stellen.

Syntax von Funktionen

Schematisch ist im folgenden die Syntax für eine Funktion dargestellt. Sie besteht aus einem Funktionsprototypen und einer Funktionsdefinition. Der Funktionsprototyp wird auch Funktionsdeklaration genannt. Eine Funktion kann beliebig viele Übergabeparameter erhalten, dies bedeutet, dass auch keine Parameter übergeben werden können. Es müssen jedoch immer so viele Paramter wie in der Funktionsdeklaration vorgeschrieben übergeben werden.

Rückgabetyp Funktionsname(Übergabetyp, ...);

// Methodenkopf
Rückgabetyp Funktionsname(Übergabetyp Übergabename, ...)
{
    // Methodenrumpf
    
    // Optionaler Rückgabe an Aufrufende Funktion
    return Wert;
}

Im speziellen ist untenstehend zu sehen wie eine Funktion deklariert und definiert wird, welche zwei Zahlen addiert.

int addieren(int, int);

int addieren(int zahl1, int zahl2)
{
    int resultat = zahl 1 + zahl2;
    return resultat;
}

int res = addieren(5, 5);
// res = 10

Die Funktion kann noch von der Lesbarkeit optimiert werden, indem man sich die zusätzliche Variable spart und die Berechnung in das Ergebnis Inline im return berechnet. Dies ergibt in diesem kein anderes Ergebnis.

int addieren(int, int);

int addieren(int zahl1, int zahl2)
{
    return zahl 1 + zahl2;
}

int res = addieren(5, 5);
// res = 10

Funktionen ohne Rückgabewert gibt es selbstverständlich wie oben erwähnt auch. Sie haben den speziellen Typ void. Untenstehend ist ein Beispiel für eine solche Funktion zu sehen.

#include <string>
using namespace std;

void textAusgeben(string);

void textAusgeben(string text)
{
    cout << text << endl;
}

textAusgeben("Test");
// Ausgabe: Test

Struktogramme von Funktionen

Die Syntax wie eine Funktion referenziert wird in seinem Struktogramm ist untenstehend zu sehen. Die Funktion bekommt dann ein eigenständiges Struktogramm, welches selbstverständlich ebenfalls Funktionen enthalten darf.

Call by Reference & Call by Value

In den bisherigen Beispielen haben wir unbewusst Call by Value verwendet. Heißt, wenn wir eine Variable einer Funktion übergeben arbeitet unsere Funktion nicht mit der Variable, sondern einer Kopie des Wertes. Dies hat den Vorteil, dass jede Funktion für sich ein abgeschlossener Block ist. Das restliche Programm wird nicht von der Funktion beeinflusst (ausgenommen sei der Fall in dem eine Exception geworfen wird).

Problem: Gegeben sei folgendes Codestück, welches einen Dreieckstausch vornimmt.

void Dreieckstausch(int Wert1, int Wert2)
{
    int temp = Wert1;
    Wert1 = Wert2;
    Wert2 = temp;
}

Offensichtlich ergibt sich das Problem, dass wir nur einen Wert zurück geben können mit einer Funktion. Selbst wenn wir somit einen der Werte die wir übergeben zurück geben, so bleibt der andere unverändert. Dieses Problem löst Call by Reference.

Call by Reference bedeutet, dass nicht die Werte übergeben werden einer Funktion, sondern lediglich ein Zeiger auf die Position wo die Variable liegt. Es wird somit in der Funktion nicht eine Kopie des Wertes manipuliert, sondern der Wert selbst.

void Dreieckstausch(int& Wert1, int& Wert2)
{
    int temp = Wert1;
    Wert1 = Wert2;
    Wert2 = temp;
}

Das & kennzeichnet hiermit, dass nicht eine Kopie, sondern eine Referenz übergeben wird. Das oben stehende Stück Code manipuliert die Werte selbst und nicht die Kopien. Der Dreieckstausch funktioniert somit ohne Rückgabewert wie gewünscht. Ein Problem ist bei Call-By-Reference, dass es somit zu einem ungewünschten Überschreiben der Werte kommen kann.