Argumente, Parameter
Die Sprachen C und C++ erlauben es, Eingabewerte für eine Funktion festzulegen. Bei einem Funktionsaufruf werden einer Funktion somit Argumente übergeben, welche sodann innerhalb der Funktion als Parameter verfügbar sind.
Die Sprachen C und C++ erlauben es, Eingabewerte für eine Funktion festzulegen. Bei einem Funktionsaufruf werden einer Funktion somit Argumente übergeben, welche sodann innerhalb der Funktion als Parameter verfügbar sind.
Ein Argument
bezeichnet einen Übergabewert, welcher bei einem Funktionsaufruf angegeben wird. Ein Parameter
hingegen bezeichnet eine Variable, welche innerhalb der Funktion das übergebene Argument als Eingabewert speichert. Beim einem Aufruf einer Funktion wird somit von Argumenten, innerhalb der aufgerufenen Funktion jedoch von Parametern gesprochen. Da beide Begriffe beinahe dasselbe bezeichnen, werden sie im allgemeinen Sprachgebrauch mehr oder weniger vermischt. Auf ManderC wird versucht, diese Begriffe konsistent zu benutzen.
Im Allgemeinen ist der Umgang mit Argumenten und Parametern problemlos: Eine Funktion deklariert anhand der Parameterliste, wieviele und was für welche Parameter sie speichern kann. Beim Funktionsaufruf wird dementsprechend eine zur Funktions-Signatur passende Liste von Argumenten angegeben, welche an die Funktion übergeben werden sollen. Bei C wird sprachlich zwischen zwei Methoden unterschieden, wie Argumente übergeben werden können. In C++ kam eine dritte Methode hinzu.
In C gilt grundsätzlich, dass eine Funktion eine abgeschlossene und vom restlichen Code unabhängige Einheit bildet, womit die innerhalb der Funktion definierten Parameter die übergebenen Argumente nicht verändern. Bei der Übergabe per Wert wird somit der Wert des Argumentes in den Parameter der Funktion kopiert. Der Wert des ursprünglichen Argumentes bleibt unberührt, der Parameter wird am Ende der Funktion verworfen.
5 4 3 2 1 Liftoff!
#include <stdio.h> void countdown(int count){ while(count){ printf("%d\n", count); count--; } } int main(){ countdown(5); printf("Liftoff!\n"); return 0; }
Die Übergabe per Wert ist speziell geeignet für die eingebauten Basistypen. Diese Methode der Übergabe ist die einzige Methode, welche auch mit rvalues funktioniert. Vorsicht ist geboten in C++, wenn ganze Objekte per Wert übergeben werden: Der Compiler ruft hierbei zu Beginn der Funktion automatisch einen Copy-Constructor und am Ende der Funktion automatisch den Destructor auf, was bei häufigen Funktionsaufrufen je nach Klasse sehr kostspielig sein kann.
Mittels der Übergabe per Wert sind beispielsweise rekursive Programme ohne Probleme zu programmieren. Der Computer reserviert bei jedem Funktionsaufruf für jeden Parameter einen neuen Speicherplatz auf dem Stack. Bei Funktionsende wird der Stack wieder abgebaut und die originalen Argumente bleiben bei der Übergabe per Wert unberührt.
Nicht selten ist erwünscht, dass eine Funktion gewisse Argumente dennoch verändern kann. Gründe hierfür gibts vielerlei und haben häufig mit dem individuellen Programmierstil zu tun. Ein wichtiger Grund ist jedoch, dass häufig Funktionen benötigt werden, welche mehr wie einen Wert zurückgeben, doch C und C++ erlauben einer Funktion zwar viele Eingabewerte, jedoch nur einen Rückgabewert (return-value). Damit übergebene Argumente verändert werden können, werden sie mittels Pointer übergeben.
Bei der Übergabe per Pointer wird nicht der eigentliche Wert, sondern der Pointer des Wertes übergeben. Damit steht der Funktion eine Adresse zur Verfügung, wo Änderungen sowohl innerhalb als auch ausserhalb der Funktion wirksam werden. In der Parameterliste der Funktion wird somit ein Pointer auf den gewünschten Typ deklariert. Um einen Pointer auf einen Wert beim Funktionsaufruf zu übergeben, wird das gewünschte Argument mithilfe des Adress-Operators &
in einen Pointer umgewandelt. Die Übergabe per Pointer funktioniert somit nur mit lvalues welche sich im Speicher befinden.
12
#include <stdio.h> #include <string.h> void countchars(const char* string, int* count){ *count = strlen(string); } int main(){ int length; countchars("Hello World!", &length); printf("%d\n", length); return 0; }
Um auf den gewünschten Wert innerhalb der Funktion zuzugreifen, muss der Pointer mittels des Dereferenz-Operators *
, des Pointer-Zugriffs-Operators ->
oder des Array-Element-Operators []
angesprochen werden. Eine Änderung des dereferenzierten Wertes innerhalb der aufgerufenen Funktion bewirkt gleichzeitig auch eine Änderung des Wertes im Bereich des Funktionsaufrufes. Dies ist nebst globalen Variablen unter C die einzige Möglichkeit, auf eine Variable ausserhalb einer Funktion zuzugreifen.
Es ist zu beachten, dass bei genauerer Betrachtung es sich bei der Übergabe per Pointer um nichts anderes als eine Übergabe per Wert handelt: Der übergebene Wert ist ein Pointer, welcher in den Parameter der Funktion kopiert wird und welcher am Ende der Funktion wieder verworfen wird. Erst durch die Dereferenzierung des Pointers wird auf den eigentlichen Wert zugegriffen. Diese Dereferenzierung bewirkt stets eine Änderung auch ausserhalb der Funktion. Nicht immer jedoch ist es gewünscht, dass eine Funktion Werte mittels eines Pointer-Argumentes verändern kann. Um zu verhindern, dass ein Argument, welches einen Pointer-Typ besitzt, von einer Funktion verändert werden kann, so kann der Parameter mit dem const
-Qualifikator deklariert werden. Weiterführende Informationen können bei der const-safe-Programmierung nachgelesen werden.
Arrays werden üblicherweise als Pointer übergeben. Dabei entspricht der übergebene Pointer einem Pointer auf den ersten Eintrag des Arrays. Mittels des Array-Element-Operators [] kann sodann innerhalb der Funktion das Array angesprochen und verändert werden, was stets auch ausserhalb der Funktion Wirksamkeit erlangt. Arrays können bei der Funktionsdeklaration anstelle mittels einer Pointer-Deklaration * auch mittels einer Array-Deklaration [] geschrieben werden, es wird jedoch vom Compiler nicht geprüft, ob die Anzahl Array-Einträge stimmen, da das Array stets in einen Pointer umgewandelt wird. Es ist jedoch zu beachten, dass die Übergabe per Referenz (siehe weiter unten) sich in diesem Punkt anders verhält.
Die Übergabe per Pointer eignet sich unter C++ insbesondere für Objekte, welche viele Member-Variablen aufweisen, welche bei einer Übergabe per Wert stets kopiert und später wieder dealloziiert werden müssten, was sehr kostspielig sein kann. Durch die Übergabe per Pointer wird ausser der Adresse des Objektes nichts weiter kopiert, was bei vielen Funktionsaufrufen sich positiv bemerkbar macht.