# Zeiger (C)

Der Zeiger oder der Pointer in der Programmiersprache C ist eine Variable, in der eine Speicheradresse gespeichert wird. Solche Zeiger werden in C häufig eingesetzt.

## Definition

Die Definition eines Zeigers besteht aus dem Datentyp des Zeigers und dem gewünschten Zeigernamen. Der Datentyp eines Zeigers besteht wiederum aus dem Datentyp des Wertes, auf den gezeigt wird, sowie aus einem Asterisk. Ein Datentyp eines Zeigers wäre also z. B. double*.
Ein definierter Zeiger, der noch nicht initialisiert wurde, zeigt auf eine zufällige Adresse. Bei einem Zugriff auf diese Adresse kann es zu einem Programmabsturz oder zum Überschreiben des an dieser Adresse gespeicherten Wertes kommen. Zeiger sollten also immer initialisiert werden.

## Zuweisungen

Die Zuweisung einer Adresse an einen Zeiger erfolgt mithilfe des Adressoperators, eines Feldes, eines weiteren Zeigers oder des Wertes von NULL.

### Adressoperator

Die Adresse einer Variablen kann vom Programmierer zwar nicht festgelegt, aber über den unären Adressoperator & ermittelt werden. Die Adresse eines Datenobjektes ist über die gesamte Laufzeit des Programms unveränderlich. Der Adressoperator kann auf alle Datenobjekte mit Ausnahme von Bitfeldern und Datenobjekten der Speicherklasse register angewendet werden.

### Inhaltsoperator

Hat man eine Adresse zur Verfügung, kann man mithilfe des Inhaltsoperators * auf den Wert, der an dieser Adresse gespeichert ist, zugreifen. Der Stern in der Definition eines Zeigers * ist nicht der Inhaltsoperator *, es wird also dasselbe Symbol für unterschiedliche Zwecke verwendet. Bei der Verwendung des Inhaltsoperators auf einen Zeiger spricht man auch von der Dereferenzierung des Zeigers.

### Nullzeiger

Soll ein Zeiger auf kein Objekt zeigen, kann man ihm den Wert NULL zuweisen. Der Zeiger ist damit ungültig und kann solange ihm keine gültige Adresse zugewiesen wird, auch nicht sinnvoll genutzt werden, eine Dereferenzierung führt meistens zu einem Laufzeitfehler nebst Programmabbruch. Sinnvoll hingegen ist der Vergleich von (Daten)Objektzeigern mit NULL, was auch die Hauptanwendung ist.
NULL ist ein Macro und wird in mehreren Header-Dateien definiert (mindestens in stddef.h). Die Definition ist vom Standard implementierungsabhängig vorgegeben und vom Compilerhersteller passend implementiert, z. B.

## Zeigerarithmetik
### Zeiger erhöhen und vermindern

Zeiger können nur mithilfe der Rechenoperationen Addition einer Ganzzahl und Subtraktion einer Ganzzahl verändert werden. Bei der Addition einer Ganzzahl wird die vom Zeiger gespeicherte Adresse entsprechend erhöht, bei der Subtraktion vermindert.
Die Summe einer in einem Zeiger gespeicherten Adresse und einer Ganzzahl ergibt in C allerdings nur bei einem Zeiger auf einen Character die um die Ganzzahl erhöhte Adresse. Vor der Addition wird die Ganzzahl nämlich noch mit der Speichergröße des Datentyps multipliziert, auf den der Zeiger verweist. Wenn ein Integer vier Bytes benötigt, ergibt die Addition einer Adresse, die auf einen Integer zeigt, mit der Ganzzahl Eins, die um vier Ganzzahlen höhere Adresse. Mit der Addition und Subtraktion auf Zeigern kann also bequem um ein oder mehr Werte nach vorn bzw. hinten gesprungen werden.
Addition und Subtraktion können wie in C allgemein üblich auch hier verkürzt angeschrieben werden.

### Vergleiche von Zeigern

Um Zeiger zu vergleichen, können die Vergleichsoperationen <, >, <=, >=, == und != verwendet werden.
Die Größer-/Kleiner-Vergleiche sind jedoch nur für Elemente des gleichen Arrays definiert. Für verschiedene Objekte, die nicht Elemente des gleichen Arrays sind, ist das Ergebnis "undefined behavior".

### Differenz von Zeigern

Um zu ermitteln, wie viele Elemente zwei Zeiger auseinanderliegen, steht der in der Header-Datei stddef.h definierte primitive Datentyp ptrdiff_t zur Verfügung. Er wird verwendet, um das Ergebnis einer Subtraktion von zwei Zeigern zu speichern, deren Ergebnis gleichbedeutend mit der Entfernung der beiden Zeiger ist.
Auch diese Operation ist nur für Elemente des gleichen Arrays definiert.

## Zeiger und Felder

Zeiger und Felder können vom Programmierer in vielen Fällen mit genau derselben Syntax verwendet werden, jedoch nicht in allen.
Das Arbeiten mit Zeigern unterscheidet sich vom Arbeiten mit Feldern insofern, als die Adresse eines Feldes konstant und deshalb nicht veränderbar ist.
Wird ein Feld an eine Funktion übergeben, so wird es unabhängig von der Funktionsdeklaration immer in einen Zeiger auf sein erstes Element umgewandelt.

## Zeiger auf Zeiger

Ein Zeiger kann auf Objekte von beliebigem Datentyp zeigen, also auch auf Zeiger selbst. Dies lässt sich endlos fortsetzen, mit Zeigern, die auf Zeiger zeigen, die auf Zeiger zeigen usw. In der Praxis kommen Zeiger auf Zeiger durchaus vor, bereits sehr selten auch noch Zeiger auf Zeiger, die auf Zeiger zeigen.

## Zeiger auf Zeichenketten

Eine Zeichenkette ist immer ein Feld, dessen Feldelemente Zeichen sind. Mit einem Zeiger kann man auf den Anfang einer Zeichenkette zeigen. Zeiger auf Zeichenketten werden häufig genutzt, beispielsweise bei der Übergabe von Zeichenketten an Funktionen.

## Anwendungsgebiete
### Verwaltung von dynamischem Speicher

Dynamischer Speicher findet in C im Gegensatz zu automatischem oder statischem Speicher Verwendung in Situationen, in denen erst zur Laufzeit die erforderliche Größe bekannt ist oder die gewünschte Größe die Grenzen des automatischen/statischen Speichers im Prozess überschreitet. Um während der Laufzeit dynamischen Speicher für das Programm anzufordern, muss in C die Funktion malloc (oder die zu ihr ähnliche Funktionen calloc, realloc) verwendet werden. malloc reserviert den benötigten Speicher und liefert einen Zeiger auf diesen zurück. Ebenso muss in C die Freigabe dieses Speichers nach Gebrauch manuell mit der Funktion free erfolgen.
Um in C mit dynamischem Speicher zu arbeiten, ist es also unumgänglich, auch mit Zeigern zu arbeiten.
Beim Freigeben von dynamischem Speicher mit free ist darauf zu achten, dass der Zeigerwert (d. h. die gespeicherte Adresse) exakt die gleiche ist wie zum Zeitpunkt von malloc und dass free nur genau einmal mit dieser Adresse aufgerufen wird:

### Zeiger als Funktionsparameter

Für Funktionsparameter, die nicht als Zeiger übergeben werden (call by value), wird innerhalb der Funktion eine Kopie erzeugt. Ist eine Kopie nicht nötig oder unerwünscht, ist es auch möglich, Zeiger auf Datenobjekte an Funktionen zu übergeben (call by reference). Ein weiterer wichtiger Grund für die Übergabe von Zeigern an Funktionen ist der eingeschränkte Gültigkeitsbereich von Variablen. Es ist nur dann möglich, innerhalb von Funktionen Variablen aufrufender Programmblöcke zu verändern, wenn diese entweder global sind (was meist unerwünscht ist) oder der Funktion Zeiger auf diese Variablen übergeben werden.
Die Parameterübergabe mithilfe von Zeigern ist auch die einzige Möglichkeit, um auch Funktionen als Argumente an andere Funktionen übergeben zu können.

### Zeiger als Rückgabewert einer Funktion

Viele Funktionen der Standard-Bibliothek geben einen Zeiger als Rückgabewert zurück. Der zurückgegebene Zeiger ist dabei immer ein Zeiger auf die Anfangsadresse des Rückgabetyps. Anwendung findet diese Methode in C vor allem zur Übergabe von Zeichenketten und Strukturen.

### Datenstrukturen

Siehe den Artikel Verbund (Datentyp).

### Rekursive Datenstrukturen

Rekursive Datenstrukturen wie Listen oder Bäume sind kaum ohne Zeiger implementierbar.

### Verarbeitung von Datenobjekten beliebigen Typs

Mithilfe des typenlosen void-Zeigers lassen sich Datenobjekte beliebigen Typs verarbeiten.

## Speichergröße von Zeigern

Die Speichergröße, die ein Zeiger benötigt, hängt von der Implementierung ab und beträgt in der Regel zwischen zwei und acht Bytes. Ermittelt wird die Größe mit der Funktion sizeof. Da ein Zeiger immer nur eine Adresse speichert, ist es unerheblich, ob der Zeiger beispielsweise auf eine Integer- oder eine Double-Variable zeigt.

## Typensicherung

Zeigervariablen sind in C nicht typsicher und nur im Sinne der Speicheradresse zuweisungskompatibel, nicht jedoch in Bezug auf die referenzierten Datentypen. So ist beispielsweise die Zuweisung einer Adresse einer Double-Variablen an einen Zeiger vom Datentyp int * zulässig. Unbeabsichtigte Zuweisungen dieser Art können zu instabilen oder fehlerhafte Programmen führen.