zurück weiter

Zeiger

G.Eichelsdörfer
Staatliche Technikerschule Weilburg

Das Thema Zeiger ist bei vielen Einsteigern in C/C++ eher unbeliebt. Wohl nicht zuletzt aus diesem Grund wurden in der C++ ähnlichen Programmiersprache Java Zeiger völlig vermieden. In C/C++ ist jedoch die Kenntnis von Zeigern unverzichtbar, also gehen wir das Thema an.

Was ist ein Zeiger (englisch: Pointer)?

Ein Zeiger beinhaltet eine Referenz auf einen Datenwert oder mehrere Datenwerte. Ein Zeiger beinhaltet also keinen Datenwert sondern verweist auf einen solchen. Ein Zeiger zeigt dahin, wo ein solcher Datenwert im Arbeitsspeicher steht. Also beinhaltet ein Zeiger eine Adresse, über die auf einen Datenwert zugegriffen werden kann. Diese Adresse stellt eine Referenz zum Zugriff auf den referenzierten Datenwert dar.

Beispiel: Zeiger Auschnitt aus dem
Arbeitsspeicher
Adressen
 
P -->
 
 
 
 
...
'M'
'a'
'c'
0
...
0x00105A04
0x00105A05
0x00105A06
0x00105A07
0x00105A08
0x00105A09

In der obigen Darstellung ist P ein Zeiger, der das große M im Arbeitsspeicher referenziert. Somit muss der Zeiger P die Adresse 0x00105A05 beinhalten. Um auf das referenzierte Zeichen zuzugreifen, muss dem Zeiger P der so genannte Dereferenzierungsoperator, das Asterisk *, vorangestellt werden:
*P liefert z.B. das Zeichen 'M'

Wie wird ein Zeiger angelegt?

Die obige Situation erhalten wir beispielsweise mit folgendem C++-Code:
char *P = "Mac";
Darin ist "Mac" eine Stringkonstante und P ist eine Zeigervariable, die ein Zeichen referenziert. Hier referenziert P das erste Zeichen der Stringkonstanten "Mac". In diesem Beispiel wird der char-Zeiger P mit der Anfangsadresse einer Stringkonstanten initialisiert. Man kann einen Zeiger wie jede andere Variable auch ohne Initialisierung anlegen. Dies sähe beispielsweise so aus:
char *P;
Hier ist P eine Zeigervariable, die eine undefinierte (zufällige) Adresse beinhaltet.

Die Syntax zum Anlegen einer Zeigervariablen lässt sich wie folgt erklären:
Das dereferenzierte P ist ein Zeichen. Somit beinhaltet P eine Referenz auf ein Zeichen und ist deshalb ein Zeiger auf ein Zeichen.

Was kann man mit einem Zeiger tun?

Der im ersten Beispiel verwendete Zeiger kann auch wie ein Datenfeld verwendet werden. Wir können auf die Zeichen wie folgt zugreifen lassen:
P[0] greift auf das 'M' zu, P[1] auf das 'a' und P[2] auf das 'c'.

Der Zugriff auf die einzelnen Zeichen gelingt auch mit Hilfe der Zeigerarithmetik:
*P greift auf das 'M' zu, *(P+1) auf das 'a' und *(P+2) auf das 'c'.
Hier wird der Zeiger P, der um eine Stelle größere Zeiger (P+1) und der um zwei Stellen größere Zeiger (P+2) verwendet. Beachten Sie, dass (P+i) ein Zeiger ist und *(P+i) der Wert, auf welchen (P+i) zeigt. *P+i hingegen ist der von P referenzierte Wert (*P), welcher um i vergößert wird. Der Dereferenzierungsoperator bindet stärker als der Additionsoperator.

(P+1) ergibt im obigen Beispiel die Adresse 0x00005A06. Dies liegt jedoch ausschließlich daran, dass ein char-Wert ein Byte beansprucht. Allgemein referenziert der Zeiger (P+1) den auf *P nachfolgenden Wert im Arbeitsspeicher. Dies soll das folgende Beispiel verdeutlichen:
int Feld[] = {9,8,7}, *IP = Feld;
cout << IP << ": " << *IP << endl
 << (IP+1) << ": " << *(IP+1) << endl
 << (IP+2) << ": " << *(IP+2) << endl;
Hier sind Feld ein mit drei Ganzzahlen initialisiertes Datenfeld und IP ein Zeiger auf einen int-Wert. IP wird mit der Anfangsadresse von Feld initialisiert. Unter der Voraussetzung, dass int-Werte 32 Bit bzw. 4 Byte beanspruchen, liefert diese Sequenz beispielsweise die folgende Ausgaben:

0012FF74: 9
0012FF78: 8
0012FF7C: 7
Links steht jeweils der Inhalt des Zeigers IP, (IP+1), (IP+2). Hinter dem Doppelpunkt folgt der durch den Zeiger referenzierte Wert. Die Adressen der Zeiger liegen jeweils um 4 auseinander, weil ein int 4 Bytes beansprucht.