Texte - Anleitungen - C - Pointer
Pointer

Pointer (= Zeiger)

Was ist ein Pointer?

Ein Pointer ist im übertragenen Sinn ein Pfeil, der auf einen Bereich im Hauptspeicher zeigt. Während ein Programm ausgeführt wird, werden bekanntlich Variablen erzeugt. Diese Variablen werden alle im Hauptspeicher gehalten. Und genau dorthin zeigen auch die Pointer.

Was kann ein Pointer?

Ein Pointer kann den Wert abrufen vom Speicherbereich, auf den er zeigt (=Indirektion). Er kann quasi den Inhalt dort herauslesen.

Aber er kann auch einfach nur die Speicheradresse ausgeben vom Speicherbereich, auf den er zeigt.

Wie deklariere ich einen Pointer?

Zur Erinnerung, was Deklaration überhaupt bedeutet: Die Deklaration ist ein Vorgang, bei dem ich dem Programm mitteilen will, dass irgendwo im Programm das deklarierte Objekt benutzt wird. Das Programm soll also darauf „gefasst“ sein, dass ich vorhabe eine Variable mit dem angegebenen Namen zu verwenden.

Je nachdem was die deklarierte Variable speichern soll, muss Speicher reserviert werden. Das hängt ganz vom Typ der Variable ab.

Nun zur eigentlichen Deklaration eines Pointers:

Jeder Zeiger zeigt auf eine Speicherzelle, wo aber nur ein bestimmter Typ gespeichert werden kann. Das heißt ein Zeiger, der jetzt auf eine Adresse zeigt, wo ein Integer Wert gespeichert ist, kann im nächsten Moment nicht auf eine Adresse zeigen, die einen String enthält.

Man gibt deshalb bei der Deklaration eines Zeigers an, auf welchen Typ von Wert er zeigen wird, mit folgender Syntax:

            Syntax:                TypzeigerName;

            Beispiele:                intneuerIntZeiger;

                                     StringhierNochEiner;

                                        charfuerEinzelneZeichen;

                                        floatzahl;

Für gewöhnlich stellt man vor den Zeigernamen allerdings noch ein „p“ (als Kürzel für „Pointer“) voran, damit, wenn ein anderer Programmierer den Code zum ersten Mal liest, dieser auch gleich weiß, wo überall ein Zeiger zu sehen ist. Das heißt unsere Beispiele sollten ganz korrekt wie folgt aussehen:

            Beispiele:                intpneuerIntZeiger;

                                     StringphierNochEiner;

                                        charpfuerEinzelneZeichen;

                                        floatpzahl;

Wie benutze ich einen Pointer?

Wie bereits erwähnt, zeigen Zeiger auf Speicheradressen. Das heißt, wenn man einen Zeiger auf die Adresse einer Variablen zeigen lassen möchte, kann man nicht einfach den Variablennamen dem Zeiger zuweisen.

Beispiel:

int x = 5;

int* pzeigtAufZahl;                     //Deklaration eines Int-Zeigers

pzeigtAufZahl = x;                      //F A L S C H

pzeigtAufZahl = &x;                   //richtig

Nun, wofür steht dieses seltsame &-Zeichen? Wenn wir nur „x“ stehen hätten, würden wir auf den Wert von x zugreifen. Wir wollen aber nicht den Wert, da ein Zeiger stets auf eine Adresse im Speicher zeigen muss. Wir wollen also die Adresse der Variablen x.

Man bekommt ja manchmal von Windows die Fehlermeldung zu lesen: „Fehler beim Zugriff auf Speicheradresse xxx0EFFF-x00EAAB0“ – und genau so eine Speicheradresse liefert uns der &-Operator.

Durch den &-Operator erhalten wir demnach die Speicheradresse der Variablen x und weisen diese Adresse dem Zeiger pzeigtAufZahl zu.

Ja und jetzt??

Jetzt zeigt pzeigtAufZahl auf eine Adresse im Speicher, aber damit können wir ja nichts anfangen?! Was sollen wir schon mit irgendeiner kryptischen Adresse im Hauptspeicher sinnvoll tun?? Um den Wert aus dieser Adresse zu manipulieren, müssen wir direkt auf die Daten dort zugreifen. In unserem Beispiel ist dort eine Integer-Zahl gespeichert (=5). Und wie gelangen wir nun an diese Integer-Zahl? Wir müssen den Wert an dieser Adresse auslesen.

Halten wir nochmals fest: Wir haben zunächst aus dem Wert der Variablen x eine Adresse bezogen, indem wir den &-Operator vorangestellt haben. Nun wollen wir wieder durch die Adresse zurück an den Wert gelangen. Dazu benutzen wir den *-Operator.

Beispiel:

int x = 5;

int* pzeigtAufZahl;                     //Deklaration eines Int-Zeigers

pzeigtAufZahl = &x;                   //pzeigtAufZahl zeigt nun auf die Speicheradresse von x

int a = *pzeigtAufZahl + 2;          //a = 7 (ergibt sich aus 5 + 2)

Hier wird auf den Wert des Zeigers pzeigtAufZahl zugegriffen, indem ein * vorangestellt wird. Diesen Vorgang nennt man Dereferenzierung.

Zum Wert von pZeigtAufZahl wird 2 addiert, was 7 ergibt.

Man kann nun stets überall dort *pzeigtAufZahl verwenden, wo man früher x verwendet hätte. Denn *pzeigtAufZahl nimmt immer den Wert des Speichers, wo x abgelegt ist – somit denselben Wert an. Wenn man *pzeigtAufZahl verändert, wird auch x verändert. Denn durch das Verändern von *pzeigtAufZahl manipuliert man den Speicherbereich. Auf der anderen Seite verändert man durch das Ändern von x aber auch *pzeigtAufZahl. Das heißt die beiden (x und * pzeigtAufZahl) sind jetzt Synonyme.

Kurz zusammengefasst:

      Deklaration eines Zeigers durch:   *

      Objekt/Wert à Adresse durch:   &

      Adresse à Objekt/Wert durch:   *

Wichtig ist, dass vor der ersten Benutzung von *pzeigtAufZahl, dem Zeiger pzeigtAufZahl eine Speicheradresse zugewiesen wurde (z.B. durch Anweisung: pzeigtAufZahl = &x;). Ansonsten würde die Dereferenzierung zu einem Zufallsergebnis führen und man würde indirekt auf irgendeinen Speicherbereich zugreifen und das würde in Folge vermutlich zu einer Speicherverletzung führen. Windows müsste dann das Programm aufgrund einer Speicherverletzung schließen…ja so kommt es zu Abstürzen von Programmen.

Can
eingereicht von Usher