- Referenzparameter
-
Referenzparameter (englisch call by reference oder pass by reference) sind Parameter von Unterprogrammen in Programmiersprachen, mittels derer ein Unterprogramm die übergebenen Argumente wie dessen übergeordnete Programm verwenden und ändern kann. Jede Veränderung bleibt auch nach Verlassen des Unterprogramms erhalten, da keine Kopien für das Unterprogramm erzeugt werden. Der Nachteil hierbei besteht darin, dass eine ungewollte Beeinflussung von Hauptprogrammvariablen im Unterprogramm möglich ist. Der Name kommt daher, dass der Compiler in den meisten Programmiersprachen die Adresse des Speicherbereichs einer Variablen oder eines Feldelements übergibt (also einen Zeiger auf die Variable oder das Feldelement), die als Referenz (Verweis, Alias) aufgefasst werden kann.
Normalerweise stehen neben Referenzparametern auch Wertparameter zur Verfügung, seltener Wertergebnisparameter.
Inhaltsverzeichnis
Beispiel
In der Sprache Pascal muss beim Unterprogrammaufruf für jeden Referenzparameter eine Variable, ein Feld- oder Strukturelement als tatsächlicher Parameter angegeben werden:
(* Uebergabe der Variablen X als Referenzparameter in PASCAL *) PROGRAM Demo(input,output); PROCEDURE Inkrementiere(VAR N: Integer);BEGIN N:=N+1; END; VAR X: integer; BEGIN Write('Bitte X eingeben'); ReadLn(X); Inkrementiere(X); Write('Der Nachfolger von X ist: '); WriteLn(X);END.
Die Funktion
Inkrementiere
hat den ReferenzparameterN
(Zeile 4), der in Zeile 13 durch die VariableX
als tatsächlicher ParameterX
ersetzt wird. Die UnterprogrammeWrite
undWriteLn
(Zeilen 11 und 13) verwenden Wertparameter, währendReadLn
einen Referenzparameter verlangt (Zeile 11), für den hier auchX
eingesetzt wird. Dadurch ist z. B.WriteLn(2*X)
ohne Weiteres möglich, währendReadLn(2*X)
einen Syntaxfehler bei der Übersetzung erzeugt.Hier ein kleines Beispiel in C++:
#include <iostream> void do_the_square(double& x){ x = x*x; } int main(){ double value = 2; do_the_square(value); std::cout << "The square_meters are: " << value << std::endl; }
Die Funktion
do_the_square()
arbeitet hier auch mit einer Referenz, und da eine Referenz nur ein Verweis auf eine Variable ist und so kein Wert zurückgegeben werden muss, reicht es, hier im Kopf der Funktion einmal eine Referenz zu setzen.Beim Aufruf der Funktion muss nur der Wert
value
(Zeile 8) übergeben werden. Anschließend hat die Funktion den Wert quadriert undvalue
diesen Wert über den Verweis angenommen.Formale und tatsächliche Parameter
Im Beispiel wird der Referenzparameter
N
(SchlüsselwortVAR
) verwendet, der bei der Deklaration des Unterprogramms erzeugt wird. WirdVAR
weggelassen, so wird ein Wertparameter erzeugt. Beim Aufruf wird der tatsächliche ParameterN
übergeben.Referenzparameter Wertparameter formale Parameter einfache Variablen und strukturierte Variablen einfache Variablen und strukturierte Variablen tatsächliche Parameter nur Variablen, Felder, Feldelemente, Strukturelemente; keine Konstanten und Ausdrücke beliebige Ausdrücke wie 1.0, 2*X, sin(x), y[i] Übergabe Als Adresse übergeben (geringer Aufwand bei Feldern) Als Kopie (hoher Aufwand bei Feldern) Zuweisung innerhalb Unterprogramm möglich möglich oder verboten (je nach Programmiersprache) Rückgabe des Wertes bei Unterprogrammende ja nein Moderne (optimierende) Compiler können bei Übergabe von Wertparametern ermitteln, ob eine Kopie nötig ist und gegebenenfalls darauf verzichten.
Simulation von Referenzparametern durch Zeiger
Das folgende Beispiel ist in der Sprache C geschrieben, welche keine Referenzparameter kennt. Durch Benutzung von Zeigern kann aber ein ähnliches Verhalten realisiert werden.
/* Uebergabe der Variablen x als Zeigerparameter p in C */ #include <stdio.h> void increment_p(int* p){ (*p) = (*p) + 1; } int main() { int x; x = 3; increment_p(&x); printf("Das Ergebnis ist %d\n", x); }
In Zeile 15 wird der Adressoperator
&
verwendet, so dass die Adresse der Variablenx
an die Funktion übergeben wird. Diese wird an den Zeigerparameterp
(Zeile 5) übergeben.Referenzparameter in Form von Referenzen
In der Sprache C++ können Referenzparameter ebenso wie in C als Zeiger realisiert werden. Es wurde aber auch eine Spracherweiterung eigens zu diesem Zweck eingeführt. Diese Spracherweiterung nennt sich Referenz und hat folgende Notation:
void increment_r('''int& r''') { r = r + 1; }
Im Vergleich dazu noch einmal das Beispiel für Zeiger:
void increment_p('''int* p''') { (*p) = (*p) + 1; }
Bei der Variante
increment_r
entfallen also die Zeigerdereferenzierungen im Funktionsrumpf.Aufruf der Funktion:
... increment_r('''x'''); ...
Im Unterschied zu der Variante mit
increment_p
wird also hier beim Aufruf nicht der Adressoperator & verwendet.Sonderfall Java
In der Sprache Java wird bei primitiven Datentypen automatisch ein Wertparameter verwendet. Bei Objekten wird die Objektreferenz als Wertparameter durch Kopie übergeben. Die aufgerufene Methode kann also den Zustand des referenzierten Objekts verändern, jedoch nicht die ursprüngliche Referenz selbst – sie zeigt also nach der Rückkehr aus dem Methodenaufruf auf dasselbe Objekt wie zuvor. Die Terminologie vieler Java-Publikationen verdeckt diesen Umstand. [1]
Dies zeigt folgendes Beispiel:
import java.util.Date; public class Test { public static void main(String args[]) { Date s = new Date(100000000000l); System.out.println("main 1: " + s); call(s); System.out.println("main 2: " + s); } public static void call(Date s) { System.out.println("call 1: " + s); s.setTime(200000000000l); System.out.println("call 2: " + s); } }
Die Ausgabe ist:
main 1: Sat Mar 03 10:46:40 CET 1973 call 1: Sat Mar 03 10:46:40 CET 1973 call 2: Mon May 03 20:33:20 CET 1976 main 2: Mon May 03 20:33:20 CET 1976
Allerdings wird eine geänderte Referenz nicht zurückgegeben. Dies verdeutlicht folgendes Beispiel:
import java.util.Date; public class Test { public static void main(String args[]) { Date s = new Date(100000000000l); System.out.println("main 1: " + s); call(s); System.out.println("main 2: " + s); } public static void call(Date s) { System.out.println("call 1: " + s); s = new Date(200000000000l); // hier liegt der Unterschied zu obigem Beispiel System.out.println("call 2: " + s); } }
Die Ausgabe ist:
main 1: Sat Mar 03 10:46:40 CET 1973 call 1: Sat Mar 03 10:46:40 CET 1973 call 2: Mon May 03 20:33:20 CET 1976 main 2: Sat Mar 03 10:46:40 CET 1973
Verwendende Programmiersprachen
Einzelnachweise
Siehe auch
- Wertparameter, auch call by value oder pass by value;
- Wertergebnisparameter.
Kategorien:- Programmiersprachelement
- Programmierparadigma
Wikimedia Foundation.