Variablen, die auf Variablen zeigen
Ein Zeiger ist eine Variable, deren Wert eine Adresse ist.
#include <stdio.h> int main(void) { int x = 10; int *p = &x; // p speichert die Adresse von x printf("&x = %p\n", (void *) &x); printf("p = %p\n", (void *) p); printf("*p = %d\n", *p); // Wert an dieser Adresse lesen *p = 7; // über p in x schreiben printf("x = %d\n", x); return 0; }
$ gcc -Wall zeiger.c -o zeiger $ ./zeiger &x = 0x7fffecea352c p = 0x7fffecea352c *p = 10 x = 7
- Deklarieren:
int *p;— p ist ein „Zeiger auf int“. - Adresse zuweisen:
p = &x;— p zeigt jetzt auf x,pund&xsind gleich. - Dereferenzieren:
*pliest den Wert an der Adresse, auf die p zeigt. - Schreiben:
*p = 7;ändert x, ohne dass x im Befehl vorkommt. - NULL:
int *p = NULL;— p zeigt auf nichts;*pbringt das Programm dann zum Absturz (Segmentation fault). - Passender Typ:
double *q = &x;mitint x→ gcc meldet „incompatible pointer type“. - Zwei Bedeutungen von *:in der Deklaration: „ist ein Zeiger“, im Ausdruck: „gehe zur Adresse“.
Ziehe die orange Pfeilspitze von p auf eine der Variablen oder auf NULL (Tastatur: Pfeilspitze fokussieren, dann Pfeiltasten). Beobachte, wie sich p, *p und die anderen Ausdrücke ändern, und schreibe mit *p = 42 durch den Zeiger.
Halte fest: p ist eine Adresse, *p ist der Wert, der dort steht. Wer über *p schreibt, ändert die Variable, auf die p gerade zeigt — ein NULL-Zeiger zeigt auf nichts, dort darf man weder lesen noch schreiben.
Zeiger: int *p = &x; speichert die Adresse von x. *p ist der Wert an dieser Adresse — lesen und schreiben. NULL bedeutet: zeigt auf nichts.
Zeiger als Parameter
Parameter sind Kopien — bekommt eine Funktion aber Adressen, kann sie die Variablen des Aufrufers ändern.
#include <stdio.h> void tausche(int *a, int *b) { int hilf = *a; *a = *b; *b = hilf; } int main(void) { int x = 3, y = 8; tausche(&x, &y); // Adressen übergeben printf("x = %d, y = %d\n", x, y); return 0; }
$ ./tausch x = 8, y = 3
- Ohne Zeiger:
void tausche(int a, int b)tauscht nur die Kopien — x = 3, y = 8 bleibt. - Parameter:
int *animmt eine Adresse entgegen;*a = …schreibt ins Original. - Aufruf:
tausche(&x, &y)— Adressen übergeben, nicht Werte. - Kopie der Adresse:auch die Adresse wird kopiert, zeigt aber auf dieselbe Speicherstelle.
- scanf:
scanf("%d", &x)braucht die Adresse, damit es den gelesenen Wert in x schreiben kann. - Ohne &:
scanf("%d", x)→-Wallwarnt „expects argument of type 'int *'“, beim Start droht ein Absturz.
Zeiger als Parameter: Parameter als int *a deklarieren, mit &x aufrufen, innen mit *a arbeiten — so ändert die Funktion das Original.
Allgemeine Hinweise
Zeiger immer initialisieren
int *p; zeigt irgendwohin. Weise erst &x oder NULL zu, bevor du *p benutzt.
Der Stern gilt nur für einen Namen
Bei int *p, q; ist nur p ein Zeiger — q ist ein ganz normaler int.
Vor dem Dereferenzieren prüfen
if (p != NULL) schützt vor dem Absturz, wenn ein Zeiger (noch) auf nichts zeigt.
