Datentypen in "C", Teil 3

Zeiger (Pointer)

Ein Zeiger ist eine Variable, die die Adresse einer Variablen enthält.

Zeigervariablen können auf fast jeden beliebigen Datentypen definiert werden.
Die Definition einer Zeigervariablen enthält die Bezeichnung des Datentypen, auf welchen der Zeiger gesetzt werden soll und den Variablennamen der Zeigervariable, welchem jedoch zur Kennzeichnung ein * vorangesetzt wird. Soll also eine Zeigervariable mit Namen intpointer definiert werden, die auf ein Integer-Element zeigen kann, so definieren wir:

         int     *intpointer;

Haben wir nun in unserem Programm eine Variable intvar des Datentyps int, so können wir unsere Zeigervariable auf diese Integervariable zeigen lassen:

         intpointer = &intvar;

Um nun den Wert zu bestimmen, der in intvar gespeichert ist, können wir mit dem Inhaltsoperator (*) über die Zeigervariable auf den Speicherplatz zugreifen.

         printf ("Der Wert von intvar ist %d\n", *intpointer);

 

Beispiel:

         int      i, x, *ip;

 

         i = 5;

         ip = &i;       /* ip zeigt nun auf i */

         x = *ip;       /* x enthaelt nun den Wert 5 */

         *ip = 3;       /* i enthaelt jetzt den Wert 3 */

Wichtig: Jede Zeigervariable muss vor deren Verwendung auf ein gültiges Ziel gesetzt werden, sonst droht ein Absturz!

Zusätzlich gibt es noch den generischen Zeiger (void *), der auf auf einen beliebigen Datentypen zeigen kann. Mit diesem generischen Zeiger können jedoch keine Operationen durchgeführt werden, da der Zieldatentyp dem Compiler nicht bekannt ist.

         void            vp;

         int               ip;

         double         *dp;

         vp = ip;       /* void-Pointer und andere Pointer können sich gegenseitig */

         dp = vp;      /* zugewiesen werden */

Zeiger und Vektoren

Arrays und Pointer sind in C eng miteinander verknüpft. Um eine Zeigervariable auf ein bestimmtes Element innerhalb eines Arrays zeigen zu lassen, kann der Adressoperator (&) verwendet werden:

         ip = &array2dim[2][3];

Soll der Zeiger auf das erste Element eines Arrays gesetzt werden, so kann eine vereinfachte Schreibweise gewählt werden:

         ip = array2dim; /* Setzt den Zeiger ip auf das erste Element von array2dim */

Arrayvariablen können bei deren Definition auch initialisiert werden, indem die Initialisierungswerte innerhalb einer Blockanweisung angegeben werden:

         int iarray[] = {10, 20, 30};

Die Grössenangabe für das Array kann hier weggelassen werden, da der Compiler die Grösse des Arrays anhand der Anzahl von Initialisierungswerten bestimmen kann.

Der Trick mit dem dynamischen Array

Wird eine Zeigervariable definiert und mit Hilfe dieser Variablen vom Betrriebsystem dynamischer Speicher angefordert, so kann danach auf die Zeigervariable zugegriffen werden, wie wenn es sich um ein Array handeln würde:

            int        *iarray;

 

            main ()

            {

                        int        i;

 

                        iarray = calloc (100, sizeof (int));         /* Reserviert Speicher fuer 100 Integerwerte */

 

                        /* Und nun fuellen wir unser dynamisches Array mit Zufallszahlen */

                        for (i=0; i<100, i++) {

                                   iarray[i] = rand ();

                        }

                        free (iarray);     /* Speicher sollte am Programmende freigegeben werden */

            }


Der Nullzeiger

Um Zeigervariablen als ungültig zu kennzeichnen wird ihnen meistens der Wert NULL zugewiesen (ip = NULL). Damit können Zeigervariablen während des Programmablaufs auf ihre Gültigkeit hin überprüft werden:

         if (ip == NULL) printf ("Zeiger zeigt nirgendwohin\n");

Rechnen mit Zeigern

Mit Zeigervariablen können eine Reihe von Operationen durchgeführt werden:

Vektoren von Zeigern (Zeigerarrays)

Da Zeiger auch nur normale Variablen sind, können sie auch zu Arrays zusammengefasst werden. Dies wird oft gemacht um eine Anzahl von Fehler- oder anderen Meldungen zu Programmbeginn festzulegen.
Beachten Sie bitte folgendes Beispiel:

         char *errmess[] = {
                   "Datei konnte nicht geöffnet werden!",
                   "Datei kann nicht gespeichert werden!",
                   "Kein Speicher mehr frei!",
                   "Ungültige Operation!",
                   NULL}

Der Nullzeiger am Schluss wird oft eingefügt, um das Ende des Stringarrays eindeutig zu kennzeichnen.