FH München, FB 07 Informatik/Mathematik
Prof. Dr. R. Schiedermeier - Vorlesung "Programmieren I"

[Previous] [Title page] [Up] [Next]

Inhaltsverzeichnis dieser Seite:

  • 3.5 Wertzuweisungen
  • 3.5.1 Zeitliche Trennung
  • 3.5.2 "L-value" und "R-value"
  • 3.5.3 Wertzuweisung als Ausdruck
  • 3.5.4 Seiteneffekt und Berechnungsreihenfolge
  • 3.5.5 Definition mit Initialisierung
  • 3.5.6 Wertzuweisung mit Operatoranwendung
  • 3.5.7 Inkrement- und Dekrementoperatoren


  • 3.5 Wertzuweisungen

    Wertzuweisungen sind eine Form von einfachen Anweisungen. Andere Arten von Anweisungen sind z.B. zusammengesetzte Anweisungen. Durch Anweisungen wird der Ablauf eines Programms kontrolliert.

    Mit einer Wertzuweisung (engl.: "assignment") wird einer Variablen ein neuer Wert zugewiesen. Ein vorher gültiger Wert wird dabei kommentarlos und ersatzlos überschrieben. Wertzuweisung werden deshalb als "destruktiv" bezeichnet.

    Eine Wertzuweisung besteht aus einer linken (das Ziel) und einer rechten Seite (die Quelle):

    	var = expr;
    

    Links muß eine Variable genannt werden, rechts kann ein beliebiger Ausdruck stehen.


    3.5.1 Zeitliche Trennung

    Eine Wertzuweisung läuft in zwei Schritten ab, die nacheinander abgewickelt werden:
    1. der Wert des Ausdrucks auf der rechten Seite wird ausgerechnet;
    2. dieser Wert wird an die Variable auf der linken Seite zugewiesen;

    Aus dieser Sicht macht eine Wertzuweisung der Form

    	a = a + 1;
    
    Sinn, die aus mathematischer Sicht falsch ist (eine Variable kann nicht gleichzeitig zwei verschiedene Werte haben).

    Dem Gleichheitszeichen kommt hier eine andere Bedeutung zu, als in der Mathematik üblich. (Ob diese Wahl geschickt war oder nicht, ist eine andere Frage.)


    3.5.2 "L-value" und "R-value"

    Im Gegensatz zu arithmetischen Ausdrücken ist die Wertzuweisung asymmetrisch: Für die zulässigen Operanden links und rechts des Zuweisungszeichens gelten unterschiedliche Regeln:

    Ein Beispiel für einen L-value ist eine Variable, wie a. Ein Beispiel für einen R-value ist der Wert eines arithmetischen Ausdrucks, wie 2+3. Offenkundig kann man an a zuweisen, aber nicht an 2+3.

    Ein- und dieselbe Variable spielt links und rechts des Zuweisungszeichens eine unterschiedliche Rolle:

    Ein Ausdruck kann sowohl einen R-, wie auch einen L-Value, als Wert haben. Das hängt in erster Linie vom Operator, aber auch vom Kontext des Ausdrucks ab. Die arithmetischen Operatoren liefern alle R-values.

    Jeder L-value ist auch als R-value verwendet werden, aber nicht umgekehrt. Das wird an der Zwitterrolle von Variablen in Abhängigkeit von Position in einer Wertzuweisung deutlich.


    3.5.3 Wertzuweisung als Ausdruck

    In C(++) spielt das Zuweisungszeichen "=" syntaktisch die Rolle eines Operators niederer Priorität (siehe Operatorentabelle), vergleichbar mit den arithmetischen Operatoren.

    Demzufolge ist eine Wertzuweisung nichts anderes als ein Ausdruck. Der "Wert" einer Wertzuweisung ist der zugewiesene Wert (ein R-value).

    Auswirkungen:

    Kettenzuweisungen
    Ein Wert kann in einer Zuweisung nacheinander an mehrere Variablen zugewiesen werden, wie z.B. in:
    	a = (b = 2);
    
    Zunächst wird die hintere Wertzuweisung ausgewertet (b bekommt den Wert 2) und das Ergebnis des Ausdrucks (d.h. die 2 als zugewiesener Wert) dann in der vorderen Wertzuweisung verwendet (a bekommt auch Wert 2).

    Derartige mehrfachen Zuweisungen werden als Kettenzuweisungen bezeichnet.

    Ohne die Klammern ("a = b = 2;") kommt es zum gleichen Resultat, weil der Zuweisungsoperator von rechts nach links bindet. Der rechte (= hintere) Operator wird zuerst ausgewertet, anschließend der linke (= vordere):

    Diese Festlegung ist sinnvoll, weil die gegenläufige Bindungsrichtung bei einem Ausdruck wie "a = b = 2;" einen Fehler liefern würde.

    Kettenzuweisungen werden oft benutzt, um z.B. eine ganze Reihe von Variablen mit einem einheitlichen Startwert zu versorgen.

    Wertzuweisungen als Teilausdrücke
    Wertzuweisungen können als Unterausdrücke in umfassenden Ausdrücken verwendet werden. (Genau genommen passiert bei einer Kettenzuweisung nichts anderes.)

    Der folgende Ausdruck

    	2 + (a = 3)
    
    liefert den Wert 5, weist aber "nebenbei" (siehe "Seiteneffekte") der Variablen a den Wert 3 zu.

    Von dieser Nutzung des Zuweisungsoperators ist aber i.allg. abzuraten, weil dabei schwer nachvollziehbare Fehler durch Implementierungsabhängigkeiten auftreten können (für ein übles Beispiel s.u.).

    Ausdrücke als Anweisungen
    Nachdem Wertzuweisungen als "einfache Anweisungen" eingeführt worden sind, müssen auch andere Ausdrücke in dieser Art zu verwenden sein.

    Tatsächlich kann jeder Ausdruck als Anweisung benutzt werden, allerdings hat diese Freiheit i.d.R. (d.h. für Ausdrücke ohne Seiteneffekte) nicht viel Sinn. Die Auswertung von

    	2;
    
    als Anweisung wird zwar ausgeführt, hat aber weiter keine Auswirkungen auf den Programmablauf (außer einem winzigen Verbrauch an Rechenzeit, sofern der Compiler die "Anweisung" nicht wegen erwiesener Sinnlosigkeit aus dem Programm streicht.).


    3.5.4 Seiteneffekt und Berechnungsreihenfolge

    Zuweisungen als Ausdrücke unterscheiden sich in einem wichtigen Punkt von den bisher betrachteten anderen Ausdrücken, wie z.B. den arithmetischen Ausdrücken:

    Die Auswertung einer Zuweisung hinterläßt beobachtbare Spuren im Zustand des Programm, die Auswertung eines arithmetischen Ausdrucks dagegen nicht.

    Betrachten Sie z.B. die beiden Ausdrücke

    	a + 2*(a + 1);
    
    und
    	a = 2*(a + 1);
    
    Am Ende eines Programms kann nicht festgestellt werden, ob der erste Ausdruck überhaupt nicht, 1x oder 1000x ausgewertet wurde. Dagegen läßt sich sehr wohl feststellen, daß und ggf. auch wie oft der zweite Ausdruck ausgewertet worden ist.

    Eine nachher beobachtbare Auswirkung auf den Zustand eines Programmes bezeichnet man als "Seiteneffekt".

    In gewissem Sinne ist der erste der beiden oben genannten Ausdrücke "harmlos", weil er unter keinen Umständen Schaden anrichten kann. Seine Berechnung zieht ja keinerlei feststellbare Konsequenzen nach sich, also insbesondere auch keine unbeabsichtigten.

    Das gilt nicht für den zweiten Ausdruck: Seine Auswertung hinterläßt Spuren, ob gewollte oder ungewollte.

    An dieser Stelle kommen die möglichen negativen Folgen von unbeabsichtigten Seiteneffekte noch nicht zum Tragen, weil die Programme klein und überschaubar sind. In größeren Softwaresystemen versucht man dagegen, mehr oder weniger ausgedehnte Programmabschnitte frei von Seiteneffekten zu halten, so daß sie als potentielle Fehlerquelle von vorne herein ausgeschlossen werden können.

    Das folgende Beispiel veranschaulicht die Problematik von Seiteneffekten:

    	(a = 1) + (a = 2)
    
    Angenommen a hat vorher den Wert 0. Welchen Wert hat a nachher?

    Die Antwort ist: 1 oder 2. Die Seiteneffekte der beiden Zuweisungen konkurrieren im obigen Ausdruck. Das Resultat hängt davon ab, welcher Summand zuerst ausgewertet wird. Das wiederum bleibt Privatsache des Compilers: Er kann die Reihenfolge nach Belieben wählen.

    Beachten Sie, daß die Assoziativität des "+"-Operators (links nach rechts) nur die Auswertungsreihenfolge mehrerer gleichrangiger Operatoren regelt, bzgl. der Anwendung eines einzelnen Operators aber keine Aussage macht.

    Auf die Auswirkungen von Seiteneffekten wird weiter hinten noch eingegangen.


    3.5.5 Definition mit Initialisierung

    Die im vorhergehenden Abschnitt gezeigte Initialisierung bei der Definition kann man als Kurzform für eine Definition mit sofort anschließender Zuweisung auffassen. (Daß diese Vorstellung nicht ganz stimmt zeigen Konstanten.)

    Die beiden Codefragmente

    	int a = 23;
    
    und
    	int a;
    	a = 23;
    
    sind gleichwertig.


    3.5.6 Wertzuweisung mit Operatoranwendung

    Eine Wertzuweisung wird oft eingesetzt, um den Wert einer einzelnen Variablen gegenüber dem vorhergehenden Wert zu modifizieren, wie z.B. in:
    	a = a + 2;	// Wert von a um 2 hochzaehlen
    	a = a / 2;	// Wert von a halbieren
    	a = a * 10;	// Wert von a verzehnfachen
    

    Dieses wiederkehrende Muster gab Anlaß für eine passende Abkürzung: Statt

    	var = var op expr
    
    schreibt man kürzer
    	var op= expr
    

    Vorerst bleibt zwar die Schreibersparnis noch in Grenzen, die zweite Form der Wertzuweisung bringt aber eine bestimmte Absicht deutlich zum Ausdruck und trägt damit zur Lesbarkeit des Programmes bei.

    Die oben gezeigten Beispiele lassen sich kürzer schreiben als:

    	a += 2;		// Wert von a um 2 hochzaehlen
    	a /= 2;		// Wert von a halbieren
    	a *= 10;	// Wert von a verzehnfachen
    

    Zur Auslösung von Prioritäten und Auswertungsreihenfolgen kann man sich die Kurzform jederzeit durch die entsprechende ausdrückliche Wertzuweisung ersetzt denken.

    Die Warnung vor konkurrierenden Seiteneffekten gilt hier genauso wie bei normalen Wertzuweisungen.


    3.5.7 Inkrement- und Dekrementoperatoren

    Eine weitere Abkürzung wurde für den oft gebrauchten Sonderfall
    	var = var + 1
    
    geschaffen:
    	var++
    

    Der Ausdruck "a++" erhöht den Wert von a um eins und liefert den hochgezählten Wert als Ergebnis zurück.

    Dieses Konstrukt wird z.B. oft in Zählschleifen benutzt.

    Zum "Inkrement"-Operator gibt es den entsprechenden "Dekrement"-Operator "--", der den Wert der Variablen um eins herunterzählt.

    Schließlich lassen sich beide Operatoren in Präfix- und in Postfix-Schreibweise verwenden, d.h. sie können der Variable voran oder nachgestellt werden.

    Unabhängig von der Stellung des Operators zählt "++" den Wert der Variablen hoch und "--" herunter.

    Die Stellung des Operators bestimmt den zurückgelieferten Wert:

    Präfix-Operator
    liefert den veränderten Wert, d.h. den Wert der Variablen nach der Veränderung;
    Postfix-Operator
    liefert den ursprünglichen Wert, d.h. den Wert der Variablen vor der Veränderung;
    Es stellt sicher heraus, daß die Postfix-Anwendung bei weitem häufiger benutzt wird.

    Folgende Tabelle zeigt die Eigenschaften im Überblick:
      erhöhen verringern
    erst Wert bestimmen, dann verändern x++ x--
    erst verändern, dann Wert bestimmen ++x --x


    [Previous] [Top of page] [Next]

    Letzte Änderung: Fri Sep 27 07:34:17 1996