10.2    Zeiger verwenden

Wird im Programm ein Zeiger mit automatischer Speicherdauer (innerhalb eines Blocks ohne das Schlüsselwort static) verwendet, der zuvor nicht initialisiert wurde, kann dies zu schwerwiegenden Fehlern führen. Ein Zeiger, der nicht mit einer gültigen Adresse initialisiert wurde und auf den jetzt zurückgegriffen werden soll, greift stattdessen einfach auf irgendeine Adresse im Arbeitsspeicher zurück. Wenn sich in diesem Speicherbereich wichtige Daten oder Programme in der Ausführung befinden, kommt es logischerweise zu einer Schutzverletzung.

Automatische Zeiger haben innerhalb eines Blocks ohne eine Initialisierung einen undefinierten Anfangswert. Globale bzw. static-Zeiger werden ohne einen Initialisierer mit einem NULL-Zeiger implizit initialisiert.

Um beispielsweise einen Zeiger vom Typ int auf die Adresse einer int-Variable verweisen zu lassen, müssen Sie folgende Zuweisung erstellen:

int *iptr;                    // Ein int-Zeiger
int ival = 255; // Eine int-Variable
iptr = &ival; // iptr enhält die Addresse von ival

Mithilfe des Adressoperators & wurde dem Zeiger iptr die Adresse der Variable ival zugewiesen. Abbildung 10.1 stellt den Vorgang grafisch dar.

Zeiger verweisen auf die Adressen von anderen Speicherobjekten.

Abbildung 10.1    Zeiger verweisen auf die Adressen von anderen Speicherobjekten.

Das Formatzeichen %p im folgenden Beispiel trägt zum besseren Verständnis bei. Hierzu ein kleines Beispiel:

00  // Kapitel10/speicheradresse.c
01 #include <stdio.h>
02 #include <stdlib.h>

03 int main(void) {
04 int *iptr;
05 int ival = 255;
06 iptr = &ival;
07 printf("Adresse iptr: %p\n", &iptr);
08 printf("zeigt auf : %p\n", iptr);
09 printf("Adresse ival: %p\n", &ival);
10 return EXIT_SUCCESS;
11 }

Listing 10.1    Das Listing gibt die Speicheradresse von ival aus.

Das Programm gibt bei der Ausführung z. B. Folgendes aus (Windows 10):

Adresse iptr: 000000000013ff00
zeigt auf : 000000000013ff0c
Adresse ival: 000000000013ff0c

In Zeile (06) des Listings wurde dem Zeiger iptr die Adresse der Variable ival zugewiesen. In Zeile (07) wird mithilfe des Formatzeichens %p die Adresse des Zeigers iptr im Arbeitsspeicher ausgegeben. Auch hierzu müssen Sie den Adressoperator verwenden. In Zeile (08) wird hingegen die Adresse ausgegeben, auf die der Zeiger iptr verweist. Dass dies in dieser Zeile ohne den Adressoperator & funktioniert, liegt natürlich daran, dass ein Zeiger selbst auch nur Adressen speichert, die er referenziert. In Zeile (09) wird dieselbe Adresse wie in Zeile (08) ausgegeben, weil Sie in Zeile (06) den Zeiger iptr auf die Adresse der Variable ival gesetzt haben. Natürlich müssen Sie bei einer Variable wieder den Adressoperator verwenden, wenn Sie an der Adresse und nicht an dem Wert der Variable interessiert sind.

10.2.1    Explizite Typumwandlung für den byteweisen Zugriff

In speziellen Fällen ist es nötig, den Wert eines Zeigers explizit in einen anderen Typ umzuwandeln. Wollen Sie beispielsweise ein Speicherobjekt Byte für Byte auslesen, wird dafür für gewöhnlich ein char-Zeiger verwendet. Hier ein Beispiel:

char *bytePtr;
float fval = 255.255;
bytePtr = (char *)&fval;

Mit der expliziten Umwandlung zeigt jetzt ein char-Zeiger auf das erste Byte des Speicherobjekts fval und könnte somit Byte für Byte bearbeitet werden.