Einführung

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

Syntax von Funktionen

Schematisch ist im Folgenden die Syntax für eine Funktion dargestellt. Sie besteht aus einem Funktionsprototyp 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 Parameter 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 Art, wie eine Funktion in einem Struktogramm referenziert wird, 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ückgeben können mit einer Funktion. Selbst wenn wir somit einen der Werte die wir übergeben zurückgeben, 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.