[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Noch ein bisschen C



Hallo Friedger, hallo allerseits!

Friedger Lang hat mir in einer PM geschrieben, er haette schon Lust, mehr
ueber C zu erfahren, und vielleicht traefe das nicht nur fuer ihn zu.
Besonders interessierte er sich fuer den Unterschied zwischen i++ und ++i
oder auch zwischen *p++ und *(p++). Sei's drum! Hier ein bisschen
Wochenendlektuere:

Unter einem "Ausdruck" (englisch: expression) versteht man in der
Programmierung eine Rechenvorschrift, in der Konstanten, Variablen und
anderes Zeug miteinander verwurstet werden, so dass letztendlich ein
"Wert" als Ergebnis herauskommt. "a - b + 25" waere so ein Ausdruck.
Haette die Variable a den Wert 92 und die Variable b den Wert 83, so
wuerde sich als Wert des Ausdrucks 34 ergeben (stimmt's?). 

Den Wert eines Ausdrucks kann man z.B. einer Variablen zuweisen, etwa in
Pascal: 
   x := a - b + 25;
oder in C:
   x = a - b + 25;

In C fasst man nun den Begriff des Ausdrucks wesentlich allgemeiner: Hier
wird die ganze Wertzuweisung (einschliesslich der Variablen x und des
Zuweisungszeichens "=") als Ausdruck betrachtet.  Der "Wert" dieses
Ausdrucks ist eben jener, den die Variable x aufgebrummt bekommen hat.
Damit kann man dann Zuweisungen auch als Teilausdruecke verwenden: 
   a = (b = c - d) + e;
ist aequivalent mit
   b = c - d;
   a = b + e;
Eine Variable liefert also hier nicht mehr nur einen passiven Beitrag zu
einem Ausdruck, sondern ihr Wert kann bei der Auswertung des Ausdrucks
veraendert werden. Programmierer, die von einer anderen Sprache herkommen,
haben gerade mit diesem Umstand oft grosse Verstaendnisschwierigkeiten.

Nun ist C ja sehr reich an Kurzformen. Um etwa den Wert einer
int-Variablen i um 1 zu erhoehen, braucht man nicht
   i = i + 1;
zu schreiben (Mathematiker kriegen dabei sowieso eine Gaensehaut), sondern
es genuegt
   i += 1;
oder sogar
   i++;
bzw.
   ++i;
Man kann den Operator "++" also vor- oder nachstellen. So fuer sich
genommen, macht das auch keinen Unterschied. Aber die Ausdruecke "i++" und
"++i" liefern ja auch einen Wert ab, den wir beispielsweise einer anderen
Variablen zuweisen koennen:
   k = i++;
bzw.
   k = ++i;
Hier wird's jetzt ernst, denn diese beiden Formen fuehren zu verschiedenen
Resultaten. Auf die Variable i haben sie zwar beide denselben Einfluss:
Sie erhoehen den Wert um 1. In der ersten Form erhaelt aber k noch den
alten, in der zweiten Form bereits den neuen (um 1 groesseren) Wert von i.
Es gibt eine einfache Eselsbruecke: Man muss die Gebilde "i++" und "++i"
nur von links nach rechts lesen und die Bestandteile interpretieren: 
"i ++" = "erst Wert von i ablesen, dann Inhalt erhoehen",
"++ i" = "erst Inhalt von i erhoehen, dann Wert ablesen".
C ist also doch nicht so schwer, wie? Uebrigens gibt es auch den Operator
"--" = "um 1 vermindern", fuer den dieselben Regeln gelten.

Luft holen und einen Schluck trinken! Jetzt kommen wir zu den Zeigern:

Vereinbaren wir doch einmal folgendes:
   char text[] = "Wochenende", *p = text;
"text" ist somit ein Array (eine Reihe von aufeinanderfolgenden
Speicherplaetzen), in dem die Zeichenfolge "Wochenende" und noch eine
abschliessende Ascii-Null gespeichert ist (in C kennzeichnet man so das
Ende eines Strings). Ausserdem haben wir einen Zeiger p vereinbart und ihn
auf den Anfang des Arrays text gesetzt. Das Symbol "*p" bedeutet nun das
Zeichen, auf das p gerade zeigt, in unserem Falle das 'W' von
"Wochenende".  Ist etwa c eine Variable vom Typ char, so weisen wir c den
Wert 'W' zu, wenn wir schreiben: 
   c = *p;

Jetzt koennen wir in C den Inhalt von Zeigervariablen veraendern, indem
wir ihn um soundsoviele Einheiten vergroessern oder verkleinern. Geben wir
etwa die Anweisung
   p++;
so haben wir den Zeiger um ein Zeichen weitergestellt, er zeigt jetzt auf
das 'o'. Mit "++p" haetten wir natuerlich dasselbe erreicht. Und wenn wir
jetzt "*" und "++" kombinieren,
   c = *p++;
bzw.
   c = *++p;
wie wirkt sich das aus? Hierzu muss man nur wissen, dass die unaeren
Operatoren (die nur einen Operanden haben) von rechts nach links
ausgewertet werden. In beiden Faellen kommt also zuerst der Operator "++",
dann "*" zum Zuge. Fuer "++" gelten aber die oben beschriebenen
Unterschiede. Stellen wir also p wieder auf das 'W':
   p = text;
und machen zuerst
   c = *p++;
"p++" liefert als Wert einen Zeiger auf 'W', schiebt allerdings p dann
eine Position weiter zum 'o'. Der Operator "*" wird aber auf den Wert des
Teilausdrucks "p++" angewandt, weshalb in c das Zeichen 'W' gespeichert
wird. Anders bei
   c = *++p;
Hier wird erst p auf das 'o' gerueckt, dann gibt "++p" diesen neuen
Zeigerwert zurueck, und "*++p" liefert schliesslich das Zeichen 'o', das
in c abgelegt wird.

Deine Frage, Friedger, was "*p++" und "*(p++)" unterscheidet, duerfte
damit sicher beantwortet sein: Nichts naemlich. Anders waere es natuerlich
mit "(*p)++". Dies wuerde naemlich das Zeichen, auf das p gerade zeigt,
manipulieren und beispielsweise aus dem "Wochenende" ein "Xochenende"
machen.

War vielleicht ein bisschen viel, aber ich denke, entweder erklaert man
eine Sache richtig, oder man laesst es ganz bleiben.

In diesem Sinne wuensche ich Euch allen ein schoenes Xochenende!
Eberhard