Programmieren mit Visual Basic für Applikationen (VBA)

Funktionen

 aufwärts

Funktionen in der Mathematik

In der Mathematik ordnet eine Funktion einem Argument einen Funktions­wert zu.

Beispiel:  Die Funktion

successor : natürliche Zahlen Pfeil nach rechts natürliche Zahlen

ordnet einer beliebigen natürlichen Zahl n die nächst­größere natürliche Zahl n+1 zu:

successor(n)  =  n+1

Hierbei ist n das Argument und n+1 der zugehörige Funktions­wert.

 

Die Funktion

maximum : natürliche Zahlen × natürliche Zahlen Pfeil nach rechts natürliche Zahlen

ordnet einem beliebigen Paar von natürlichen Zahlen (a, b) die größere dieser beiden Zahlen zu.

maximum(a, b)  =   geschweifte Klammer
a    falls a > b
b    sonst

Hierbei ist das Paar (a, b) das Argument und das Maximum von a und b der zugehörige Funktions­wert.

Definition und Aufruf von Funktionen in Visual Basic

In Programmier­sprachen wird der Begriff der Funktion in ähnlicher Weise benutzt.

Auch eine Programm-Funktion kann einem Argument einen Funktions­wert zuordnen. In der Funktions­definition wird dabei zunächst allgemein angegeben, wie der Funktions­wert aus dem Argument zu berechnen ist. Beim Funktions­aufruf erhält die Funktion dann einen konkreten Argumentwert, führt die Berechnung durch und gibt den ent­sprechenden Funktions­wert zurück.

Beispiel:  Die Definition der Funktion successor aus dem obigen Beispiel lässt sich in Visual Basic wie folgt realisieren:

Function successor(n)
    successor = n+1
End Function

Der Name der Funktion ist successor, als Argument erhält die Funktion eine Zahl n. Der berechnete Funktions­wert wird dem Funktions­namen zugewiesen. Der Berechnungs­teil der Funktions­definition endet mit End Function.

Ein Aufruf der Funktion sieht beispiels­weise wie folgt aus:

k = successor(17)

Als Argumentwert wird hier für n der Wert 17 eingesetzt; als Ergebnis des Funktions­aufrufs wird der Wert 18 zurück­gegeben und der Variablen k zugewiesen.

 

Beispiel:  Die Definition der Funktion maximum lässt sich in Visual Basic wie folgt realisieren:

Function maximum(a, b)
    If a > b Then
        maximum = a
    Else
        maximum = b
    End If
End Function

Diese Funktions­definition orientiert sich genau an der mathe­matischen Definition der Maximum­funktion. Es wäre aber auch möglich gewesen, eine andere Berechnungs­vorschrift anzugeben, etwa die folgende.

Function maximum(a, b)
    maximum = (a + b + Abs(a - b)) / 2
End Function

Wenn auch weniger offen­sicht­lich, wird durch diese Berechnung ebenfalls das Maximum von a und b ermittelt. Hierbei ist Abs die in Visual Basic enthaltene Absolut­betragfunktion.

Ein möglicher Aufruf der Funktion ist beispiels­weise

x = maximum(z, 0)

Hierbei wird der Wert der Variablen z, sofern dieser positiv ist, und ansonsten der Wert 0 zurück­gegeben und der Variablen x zugewiesen.

Globale und lokale Variablen

Variablen dienen zur Speicherung von Werten, z.B. von Zwischen­ergebnissen von Berechnungen. Fallen Zwischen­ergebnisse bei einer Berechnung in einer Funktions­definition an, so werden diese zweck­mäßiger­weise in lokalen Variablen gespeichert. Lokale Variablen werden innerhalb der Funktions­definition deklariert. Sie haben nur innerhalb der Funktions­definition Gültigkeit, von außerhalb sind sie nicht zugänglich.

Beispiel:  Die Fakultäts­funktion ordnet einer beliebigen nicht­negativen ganzen Zahl n als Funktions­wert die Fakultät n! = 1 · 2 · 3 · 4 · ... · n zu. Mit folgender Funktion lässt sich die Fakultäts­berechnung durchführen:

Function fakultaet(n)
    Dim i, f
    i = 1
    f = 1
    Do While i<=n
        f = f * i
        i = i + 1
    Loop
    fakultaet = f
End Function

Hierbei sind i und f lokale Variablen, diese haben nur innerhalb der Funktions­definition Gültigkeit.

Im Gegensatz zu lokalen Variablen stehen globale Variablen. Globale Variablen werden außerhalb der Funktions­definition deklariert. Sie haben außerhalb und innerhalb der Funktions­definition Gültigkeit.

Beispiel:  In folgendem Programm­stück wird eine globale String-Variable trennsymbol deklariert. Die nachfolgende Funktion verkettung fügt zwei Zeichen­reihen unter Einschluss des Trennsymbols zusammen. In der Prozedur test wird die globale Variable trennsymbol mit dem Wert ";" belegt und anschließend die Funktion verkettung aufgerufen.

Dim trennsymbol

Function verkettung(s, t)
    verkettung = s & trennsymbol & t
End Function

Sub test()
    trennsymbol = ";"
    s = verkettung("alpha", "beta")
End Sub

Das Ergebnis ist "alpha;beta".

Namens­konflikte

Normaler­weise haben innerhalb einer Funktion sowohl die dort deklarierten lokalen Variablen als auch die außerhalb der Funktion deklarierten globalen Variablen Gültigkeit. Ein Problem tritt auf, wenn eine globale Variable und eine lokale Variable denselben Namen haben. Wenn also z.B. beide Variablen x heißen und wenn dann innerhalb der Funktion auf x zugegriffen wird, dann ist zunächst unklar, welches x gemeint ist. Daher gilt die Regel, dass innerhalb der Funktion die lokale Variable Vorrang hat. Die Konsequenz ist, dass innerhalb der Funktion die globale Variable gleichen Namens nicht erreichbar ist.

Beispiel:  Beim Aufruf der im Folgenden definierten Version der Funktion verkettung, etwa mit verkettung("alpha", "beta"), wird das Ergebnis "alpha+beta" zurück­gegeben.

Dim trennsymbol=";"

Function verkettung(s, t)
    Dim trennsymbol
    trennsymbol = "+"
    verkettung = s & trennsymbol & t
End Function

Sub test()
    trennsymbol = ";"
    s = verkettung("alpha", "beta")
End Sub

Es werden zwei Variablen deklariert, eine globale Variable trennsymbol und eine lokale Variable mit demselben Namen. Die globale Variable trennsymbol erhält in der Prozedur test den Wert ";". beim Aufruf der Funktion verkettung wird eine lokale Variable trennsymbol deklariert und mit dem Wert "+" belegt. Innerhalb der Funktion hat die lokale Variable trennsymbol Vorrang. Immer, wenn innerhalb der Funktion auf die Variable trennsymbol zugegriffen wird, ist die lokale Variable trennsymbol gemeint, und diese hat den Wert "+".

Die globale Variable trennsymbol wird durch den Aufruf der Funktion verkettung in diesem Fall nicht berührt. In der Prozedur test hat trennsymbol anschließend immer noch den Wert ";".

Funktionen ohne Argumente

In Programmier­sprachen gibt es auch Funktionen, die zur Berechnung des Funktions­wertes keinen Argumentwert benötigen.

Beispiel:  Die folgende Funktion berechnet die eulersche Zahl e. Um die Berechnung durch­zuführen, wird kein Argument benötigt. Es wird jedoch ein Wert zurück­gegeben, nämlich die Zahl e = 2,718....

Die Berechnung wird nach der Formel

e  =   Summe n = 0, ..., unendlich  1 / n!

durchgeführt. Da nicht unendlich viele Summanden berechnet werden können, wird nur solange gerechnet, wie die Summanden größer als 10-8 sind, dann wird die Berechnung abgebrochen, da eine ausreichende Genauigkeit erreicht ist.

Function e()
    Dim n, s, f
    n = 1
    s = 1
    f = 1
    Do While s > 1e-8
        s = s / n
        f = f + s
        n = n + 1
    Loop
    e = f
End Function

Die Funktion könnte etwa folgender­maßen aufgerufen werden:

x = e()

Hier wird die Funktion e() aufgerufen und der berechnete Funktions­wert der Variablen x zugewiesen.

Parameter­übergabe

Im Bereich der Programmier­sprachen wird bei Funktionen statt des Begriffs "Argument" meist der Begriff "Parameter" verwendet. Funktionen können einen oder mehrere oder auch gar keinen Parameter haben. Beispiels­weise hat die Funktion successor(n) einen Parameter, die Funktion maximum(a, b) hat zwei Parameter, und die Funktion e() hat keinen Parameter.

In der Funktions­definition werden die Parameter als formale Parameter bezeichnet, beim Funktions­aufruf werden die Parameter als aktuelle Parameter bezeichnet.

Beispiel:  Die folgende Funktion power berechnet an für eine Zahl a und eine nicht­negative ganze Zahl n.

Function power(a, n)
    Dim p
    p = 1
    Do While n > 0
        p = p * a
        n = n - 1
    Loop
    power = p
End Function

In dieser Funktions­definition sind a und n die formalen Parameter.

Formale Parameter spielen im Prinzip dieselbe Rolle wie lokale Variablen. Ebenso wie lokale Variablen haben sie nur innerhalb der Funktions­definition Gültigkeit, und bei Namens­konflikten mit globalen Variablen haben sie Vorrang.

Der Unterschied zu gewöhnlichen lokalen Variablen besteht darin, dass die formalen Parameter beim Aufruf der Funktion mit den Werten der aktuellen Parameter initialisiert werden. Dabei kommt es auf die Reihenfolge der Parameter an: Der erste formale Parameter erhält den Wert des ersten aktuellen Parameters, der zweite formale Parameter erhält den Wert des zweiten aktuellen Parameters usw. Dieser Vorgang wird als Parameter­übergabe bezeichnet.

Beispiel:  Beim Aufruf der Funktion power, etwa durch

z = power(2, 10)

erhält der formale Parameter a den Wert 2 und der formale Parmeter n den Wert 10. Der Funktions­aufruf ergibt also hier den Wert 210  =  1024.

Die formalen Parameter müssen also immer Variablen sein, die aktuellen Parameter müssen immer Ausdrücke sein, die Werte ergeben.1)

Die Situation ist genau wie bei einer Wert­zuweisung, bei der auf der linken Seite des Wert­zuweisungs­zeichens immer eine Variable stehen muss und auf der rechten Seite immer ein Ausdruck, der einen Wert ergibt. Tatsächlich handelt es sich bei der Parameter­übergabe um eine Wert­zuweisung – beim Aufruf der Funktion erhalten die formalen Parameter die Werte der ent­sprechenden aktuellen Parameter.

Call by value und call by reference

Eine Eigenheit von Visual Basic besteht darin, dass die Parameter­übergabe – anders als in anderen Programmier­sprachen – tatsächlich nicht immer so durchgeführt wird wie eben beschrieben. Beispiels­weise wird bei folgendem Funktions­aufruf

k = 10
x = power(2, k)

nicht der Wert (10) des aktuellen Parameters k an den formalen Parameter n der Funktion power übergeben, sondern die Referenz auf die Variable k. Dies bedeutet, dass von nun an die Variablen­namen k und n auf dieselbe Speicher­zelle verweisen. Jede Änderung des Wertes von n innerhalb der Funktion power bewirkt gleichzeitig eine Änderung des Wertes von k außerhalb der Funktion. Diese Form der Parameter­übergabe wird call by reference genannt.

In Visual Basic wird die Parameter­übergabe immer dann als call by reference durchgeführt, wenn der aktuelle Parameter eine einzelne Variable ist. Ist der aktuelle Parameter dagegen keine einzelne Variable, sondern irgendein anderer Ausdruck, so wird die Parameter­übergabe so wie im vorigen Abschnitt beschrieben durchgeführt, nämlich als call by value.

Diese unter­schiedliche Behandlung der Parameter­übergabe stellt einen schweren Entwurfs­fehler der Programmier­sprache Visual Basic dar, denn hierdurch sind Fehler gleichsam "vor­programmiert".

Wenn man in die Definition der Funktion power schaut, sieht man, dass dort der Wert des formalen Parameters n verändert wird. Ist der aktuelle Parameter eine einzelne Variable, etwa k, so wird durch die Parameter­übergabe als call by reference auch der Wert von k entsprechend verändert. Dies führt zu der grotesken Situation, dass in folgendem Programm x den Wert 1024 und y den Wert 1 erhält, denn nach dem ersten Funktions­aufruf hat die Variable k den Wert 0, weil sie sich gleichzeitig mit der Variablen n bei Ausführung der Funktion auf 0 vermindert hat.

k = 10
x = power(2, k)
y = power(2, k)

Dagegen liefert folgendes Programm sowohl für x als auch für y den Wert 1024. Denn die aktuellen Parameter sind hier keine einzelnen Variablen, sondern andere Ausdrücke, und somit wird die Parameter­übergabe als call by value durchgeführt.

k = 10
x = power(2, (k))
y = power(2, (k))

Um diese Ungereimtheiten zu umgehen, gibt es die Möglichkeit, die Parameter­übergabe als call by value zu erzwingen, indem in der Funktions­definition dem formalen Parameter das Wort ByVal voran­gestellt wird, im Beispiel also so:

Function power(a, ByVal n)

Da der Wert des Parameters a in der Funktion nicht verändert wird, spielt es keine Rolle, ob der Parameter a als call by value oder call by reference übergeben wird. Beim Parameter n dagegen, dessen Wert sich in der Funktion ändert, wird die Parameter­übergabe als call by value vor­geschrieben.

Die Frage ist, warum es überhaupt die Parameter­übergabe als call by reference gibt. Der Grund liegt darin, dass Funktionen nur einen Funktions­wert zurückgeben können. Soll eine Funktion aber mehrere Werte berechnen, so lassen sich diese Werte über Parameter, die als call by reference übergeben werden, zurückgeben.

Beispiel:  Die folgende Prozedur gibt über den Parameter q den Quotienten und über den Parameter r den Rest bei Division von a durch b zurück.

Sub quotientUndRest(a, b, q, r)
    q = a \ b
    r = a Mod b
End Sub

Der Operator \ bedeutet ganzzahlige Division, der Operator Mod liefert den Rest bei ganzzahliger Division. Der Aufruf

    quotientUndRest 17, 5, x, y

ergibt für x den Wert 3 und für y den Wert 2.

Beispiel:  Ein weiteres Beispiel für die sinnvolle Verwendung von call by reference ist folgende Prozedur exchange zum Vertauschen der Wert zweier Variablen:

Sub exchange(a, b)
    h = a
    a = b
    b = h
End Sub

Nach Ausführung des folgenden Programms

    x = 3
    y = 5
    exchange x, y

hat x den Wert 5 und y den Wert 3. Wären die Parameter mit call by value übergeben worden, hätte der Funktions­aufruf nach außen hin gar nichts bewirkt.

Obwohl die Parameter­übergabe standard­mäßig als call by reference durchgeführt wird, gibt es die Möglichkeit, dies explizit deutlich zu machen, indem in der Funktions­definition dem formalen Parameter das Wort ByRef voran­gestellt wird.

Seiteneffekte

Eigentlich erwartet man von einer Funktion, dass sie beim Aufruf den Funktions­wert berechnet und sonst nichts tut. Tatsächlich jedoch können in der Funktions­definiton noch weitere Anweisungen enthalten sein, die mit der eigentlichen Berechnung des Funktions­werts nichts zu tun haben.

Beispiel:  In der Funktion zur Berechnung von e gibt eine Ausgabe­anweisung in jeder Iteration die erreichte Annäherung an den schließlich berechneten Funktions­wert aus.

Function e()
    Dim n, s, f
    n = 1
    s = 1
    f = 1
    Do While s > 1e-8
        s = s / n
        f = f + s
        Cells(n, 1) = f
        n = n + 1
    Loop
    e = f
End Function

Normaler­weise sollten Funktionen frei von Seiten­effekten sein. Der Grund ist, dass man nicht erwartet, dass außer der Berechnung des Funktions­wertes noch andere Dinge geschehen.

Es gibt jedoch eine Klasse von Funktionen, für die dies nicht gilt. Dies sind Funktionen ohne Rückgabewert.

Funktionen ohne Rückgabewert

Funktionen, die keinen Funktions­wert berechnen, sind eigentlich sinnlos. Nur wenn sie Seiten­effekte haben, können sie überhaupt etwas bewirken. Tatsächlich spielen Funktionen, die nur Seiten­effekte haben und keinen Funktions­wert zurückgeben, eine bedeutende Rolle. In Visual Basic wird eine Funktion ohne Rückgabewert als Prozedur (subroutine) bezeichnet und statt mit Function mit Sub deklariert.

Beispiel:  Die folgende Prozedur weist der globalen Variablen trennsymbol einen neuen Wert zu.

Dim trennsymbol

Sub neuesTrennsymbol(t)
    trennsymbol = t
End Sub

Die Funktion gibt keinen Funktions­wert zurück. Als Seiteneffekt verändert sie jedoch den Wert der globalen Variablen trennsymbol. Nach Aufruf etwa von

neuesTrennsymbol "/"

hat die globale Variable trennsymbol den neuen Wert "/".

Funktionen ohne Rückgabewert werden wie Anweisungen aufgerufen (etwa: neuesTrennsymbol "/"); dagegen werden Funktionen, die einen Rückgabewert erzeugen, in der Regel innerhalb von Ausdrücken aufgerufen (etwa: x = 2 * max(a, b) + 1).

Eine Besonderheit bei Visual Basic besteht darin, dass bei Prozedur­aufrufen die Argumente nicht in Klammern gesetzt werden.

Rekursive Funktionen

Innerhalb einer Funktions­definition kann ein Aufruf derselben Funktion vorkommen. Eine Funktion kann sich also selbst aufrufen. Man bezeichnet eine solche Funktion als rekursive Funktion.

Beispiel:  Für n Element natürliche Zahlen0 lässt sich die n-te Potenz einer Zahl a rekursiv wie folgt definieren:

a n  =   geschweifte Klammer
1    falls n = 0
a n-1 · a    sonst

Diese Definition lässt sich unmittelbar in eine rekursive Funktion umsetzen:

Function power(a, n)
    If n = 0 Then
        power = 1
    Else
        power = power(a, n - 1) * a
    End If
End Function

Aufgaben

Aufgabe 1:  Schreiben Sie eine Funktion square(x), die das Quadrat einer Zahl x berechnet.

Aufgabe 2:  Setzen Sie folgende mathe­matische Funktions­definition in eine Java-Funktion um.

betrag(x)  =   geschweifte Klammer
-x    falls x < 0
x    sonst

Aufgabe 3:  Setzen Sie folgende mathe­matische Funktions­definition in eine rekursive Java-Funktion um.

n!  =   geschweifte Klammer
1    falls n = 0
n·(n-1)!    sonst

1)  Ausnahme: call by reference – siehe folgender Abschnitt

 

Weiter mit:   up

 

homeH.W. Lang   Hochschule Flensburg   lang@hs-flensburg.de   Impressum   Datenschutz   ©  
Valid HTML 4.01 Transitional