Zeiger

Ein Zeiger (engl. Pointer) ist ein typisierter Verweis auf einen Speicherbereich, sozusagen ein Link auf den Speicher. Sehen wir uns wiederum das Beispiel an, um hinter die Idee zu kommen.

Ein einfaches Beispiel

Die Funktion einfach enthält folgenden Code:

    // Variable im Speicher anlegen
    int  a = 42;
    // Zeiger auf Integer anlegen
    int* p;

    // Wert von a ausgeben
    cout << a << endl;

    // Referenzierung:
    // p auf a zeigen lassen
    p = &a;
    // Dereferenzierung:
    // Das, worauf p zeigt, verändern (also a)
    *p = 23;

    // Wert von a ausgeben
    cout << a << endl;

Durch den Befehl p = &a; lassen wir p auf a zeigen. a liegt irgendwo in unserem Speicher. p enthält nach dieser Zuweisung als Wert die Speicheradresse von a. Durch das Und (&) vor einer Variablen können wir also deren Anfangsadresse im Speicher bestimmen und einem Pointer zuweisen.

p zeigt auf a

Mit  *p = 23; verändern wir anschließend das, worauf p zeigt. An den Inhalt eines Zeigers kommen wir also über den Stern (*) vor einem Zeiger wieder heran. Danach enthält die Variable a den Wert 23.

Zeiger und Felder

Sehen wir uns die zweite Funktion array an.

    // Array im Speicher anlegen
    int  a[2] = { 42, 42 };
    // Zeiger auf Integer anlegen
    int* p;

    // Werte von a ausgeben
    cout << a[0] << " | " << a[1] << endl;

    // Referenzierung:
    // p auf a zeigen lassen
    p = a;
    // Dereferenzierung:
    // Das, worauf p zeigt, verändern (also a[0])
    *p = 23;

    // Werte von a ausgeben
    cout << a[0] << " | " << a[1] << endl;

    // Dereferenzierung mit Index:
    // Nächstes Element verändern (also a[1])
    p[1] = 216;

    // Werte von a ausgeben
    cout << a[0] << " | " << a[1] << endl;

Im Falle von Arrays benötigen wir keinen &-Operator, da C++ Arrays schon als Speicherbereich interpretiert. Ein Array ist also im Grunde nichts anderes als ein typisierter Zeiger auf einen Speicherbereich.

p zeigt auf a[0]

Genau wie bei Arrays können wir mit Zeigern nicht nur das erste Element, auf das er zeigt, verändern, sondern durch Indizes in eckigen Klammern auch im Speicherbereich dahinter liegende Elemente.

Mit Zeigern lässt sich auch rechnen. p zeigt ursprünglich auf a[0]. Der Befehl p=p+1 würde unseren Zeiger um vier Bytes auf a[1] weiterbewegen, da der Typ int auf 32-Bit Maschinen vier Bytes groß ist. Beim Rechnen und Indizieren mit Zeigern kommt also der Typ des Zeigers durchaus zum Tragen.

Häufig sieht man in C und C++ die Notation

    *p++ = x;

Das bedeutet im Klartext: Weise dem, worauf p zeigt den Wert x zu und bewege den Zeiger danach ein Arrayelement weiter.

Funktionen

Bisher haben wir einer Funktionen immer Parameter übergeben und eventuell einen Wert zurückgeliefert. Wenn wir mehrere Werte zurückliefern oder Parameter in ihrem Wert ändern wollten, hatten wir bisher dazu keine Möglichkeit. Mit Zeigern funktioniert es:

void pointer(int* x)
{
    // Wert von x quadrieren
    *x = (*x) * (*x);
}

Wer möchte, kann die Klammern auch weglassen. Aufgerufen werden kann diese Funktion danach z.B. so:

    // Variable im Speicher anlegen
    int x = 2;
    // x mit Hilfe von Zeiger verändern
    pointer(&x);

Nach Abarbeiten dieser beiden Zeilen steht in x, wie erwartet, der Wert 4.

Im Beispielcode ist noch eine Alternative zum Übergeben eines Parameters als Zeiger durch eine sogenannte Referenz aufgeführt. Referenzen sind im Grunde Zeiger, nur in anderer, manchmal ebenso verwirrender, Notation. Daher möchte ich hier nicht genauer darauf eingehen.

NULL

Ein Zeiger, der auf nichts zeigt, besitzt den Wert NULL. Dieser ist in der Standard-Headerdatei memory.h deklariert. Der Vergleich auf NULL ist z.B. sinnvoll um festzustellen, ob überhaupt Speicher belegt wurde.

zurück