|
Eigentlich sollte man ja int* pc schreiben, denn gemeint ist
ein Pointer auf int, der den Name pc hat.
Aber seit Anbeginn der Sprache C wird das Sternchen direkt vor den
Variablennamen gesetzt (dem Compiler ist es übrigens egal).
Zeiger zeigen immer auf Objekte eines bestimmten Typs. Sie müssen
daher deklariert werden. Auch in der Zeigerdefinition wird der
Operator * verwendet. Zeigerdefinitionen kann man als Muster
verstehen:
int *px; /* px ist Zeiger auf int */
char *zs; /* zs ist Zeiger auf char */
int x, y;
px = &x; /* px = (Speicher-)Adresse der Variablen x */
y = *px; /* y = Wert der Variablen x */
Zeiger sind also an bestimmte Objekttypen gebunden. Ein Zeiger auf int kann
also beispielsweise nur Adressen von int-Variablen aufnehmen. Eine
Ausnahme bildet der "Generic Pointer", der auf ein beliebiges Objekt zeigen kann.
In Verbindung mit Zeigern werden hauptsächlich zwei zueinander inverse Operatoren
benutzt:
- Der Adreßoperator &, der angewendet auf ein Objekt, die
Adresse dieses Objekts liefert.
& kann auf Variablen und Arrayelemente angewendet werden, nicht aber auf
Arraynamen selbst (Warum? Ein Arrayname hat keine Adresse, er ist
eine Adresse!). Ebenso haben natürlich Variablen in der Speicherklasse
register keine Adressen.
Beispiele für die Anwendung des Adreßoperators und
das Speichern der Adresse in einem Zeiger:
px = &x; /* px erhält als Wert die Adresse von x */
pf = &f[5]; /* pf erhält als Wert die Adresse des
6. Elementes von f */
- Der Inhaltsoperator *, der angewendet auf einen
Zeiger das Objekt liefert, das unter dieser Adresse abgelegt ist.
Beispiel:
y = *px; /* y erhält den Wert des Objektes,
dessen Adresse in px steht */
px = &x; /* px "zeigt" nun auf x */
y = *px; /* y = x; */
Die folgenden Programmbeispiele zeigen den Gebrauch dieser beiden Operatoren:
#include <stdio.h>
int main(void)
{
int x = 1, y = 2, z[10];
int *ip; /* ip ist ein Zeiger auf int */
ip = &x; /* ip zeigt nun auf x */
printf("ip: %d\n",ip);
y = *ip; /* y ist nun gleich 1 */
printf(" y: %d\n", y);
*ip = 0; /* x ist nun gleich 0 */
printf(" x: %d\n", x);
ip = &z[0]; /* ip zeigt nun auf z[0] */
printf("ip: %d\n", ip);
}
#include <stdio.h>
int main(void)
{
int zahl;
int *zeiger;
/* Laß die Zeigervariable auf die Variable zeigen */
zeiger=&zahl;
/* Setze den Wert der Variablen mit Hilfe der Zeiger-
variablen */
*zeiger = 5;
/* Gib zur Kontrolle den Wert aus */
printf("Der folgende Wert sollte 5 sein: %d\n",zahl);
return(0);
}
Die Deklaration des Zeigers ip in int *ip;
besagt, daß der Ausdruck *ip vom Datentyp int ist, bzw.
ip auf den Datentyp int zeigt. In der Zuweisung ip = &x;
wird der Zeigervariablen ip die Adresse von x zugewiesen;
man sagt auch "ip zeigt auf x". Damit hat *ip
denselben Wert wie x, nämlich 1, der in der Zuweisung
y = *ip; der Variablen y zugewiesen wird und somit den
ursprünglichen Wert 2 überschreibt. Durch die Zuweisung
*ip = 0; erhält auch x den Wert 0, wie man
mit printf bestätigen kann. Durch die Zuweisung ip = &z[0];
zeigt der Zeiger ip auf das Anfangselement des Feldes z.
Einige Grundregeln:
Die Kombination *Zeiger kann in Ausdrücken überall
dort auftreten, wo auch das Objekt, auf das der Zeiger zeigt,
selbst stehen könnte:
y = *px + 10;
y = *px + *px;
printf("%d\n", *px);
*px = 0;
py = px; /* falls py auch Zeiger auf int */
Bei der Verwendung des Operators * muß man die Operatorrangfolge
und -assoziativität genau beachten. Dies erscheint zunächst
etwas schwierig, da dieser Operator ungewohnt ist. Hier einige
Beispiele mit dem * Operator und anderen Operatoren:
y = *px + 1; /* Inhalt von px plus 1 */
y = *(px+1); /* Inhalt der Adresse px+1 */
*px += 1; /* Inhalt von px = Inhalt von px plus 1 */
(*px)++; /* Inhalt von px inkrementieren */
*px++; /* wie *(px++); (Assoziativität)
Inhalt der Adresse px; px = px plus 1*/
*++px; /* Inhalt der Adresse px+1; px = px plus 1 */
Besonders wichtig:
- * und & haben höhere Priorität als arithmetische Operatoren.
- Werden * und ++ direkt hintereinander verwendet, wird der Ausdruck
von rechts nach links abgearbeitet.
Zeiger haben nur dann sinnvolle Werte, wenn sie die Adresse eines Objektes oder
NULL enthalten. NULL ist eine globale symbolische Konstante, die in der
Standardbibliothek definiert ist und überall als NULL-Zeiger benutzt werden kann.
Für den Zeigerwert NULL ist garantiert,
daß er nirgends hinzeigt. NULL ist definiert als eine Adresse mit dem
Wert 0; Sie sollten auch immer NULL verwenden, niemals den Zahlenwert
0, denn es ist nicht sicher, ob die Länge einer Integer-Variablen auch der
Länge einer Adresse entspricht. Früher war dies oft der Fall, weshalb sich
manchmal in alten Programmen noch die Definition #define NULL 0 findet.
Bei modernen Computersystemen geht das aber schief!
|
|
|