Die Dereferenzierungsoperatoren * und der Adressoperator & sind einige der grundlegenden Werkzeuge zur Arbeit mit Speicher in C. Sie ermöglichen eine direkte Steuerung von Daten im Speicher, was C zu einer beliebten Sprache für Systemprogrammierung gemacht hat.
Historie der Frage:
Seit der Einführung der Sprache C (in den 1970er Jahren) war ihre Philosophie eng mit der niedrigen Speicherverwaltung verbunden. Die Operatoren * und & implementieren die Technik der indirekten Adressierung, die auf Prozessorlevel verwendet wird, was es ermöglicht, mit Zeigern zu arbeiten, dynamisch Speicher zuzuweisen und effiziente Datenstrukturen zu erstellen.
Problem: Fehler bei der Verwendung dieser Operatoren führen zu zahlreichen Bugs: Speicherlecks, Datenbeschädigungen, Segfaults. Der Compiler signalisiert diese Fehler nicht immer offensichtlich, insbesondere wenn die Typen der Zeiger in der Größe übereinstimmen, aber sich im Inhalt unterscheiden.
Lösung: Sich aufmerksam um den Typ des Zeigers kümmern, den Lebenszyklus des zugewiesenen Speichers überwachen, die Initialisierung und korrekte Freigabe durchführen sowie die Richtigkeit der Dereferenzierungsoperationen und der verwendeten Adressen überprüfen.
Beispielcode:
int x = 10; int *p = &x; // Adresse holen int y = *p; // Dereferenzierung (Wert an Adresse erhalten) // Arbeiten mit einem Zeiger auf ein Array int arr[3] = {1,2,3}; int *pa = arr; printf("%d", *(pa+1)); // zweites Element des Arrays
Wesentliche Merkmale:
Kann man die Adresse einer temporären Variablen nehmen, zum Beispiel: & (x + y)?
Nein, die Adresse eines Ausdrucks kann nicht genommen werden, da das Ergebnis des Ausdrucks kein Speicherobjekt ist. Die Adresse kann nur von einer Variablen, einem Array oder einer Struktur genommen werden.
Beispielcode:
int z = 5; int p = &(z + 1); // Compilerfehler
Was unterscheidet die Dereferenzierung eines Void-Zeigers?
Ein Zeiger des Typs void * kann nicht direkt dereferenziert werden, bis er in einen spezifischen Typ umgewandelt wird. Dies ist ein universeller Zeiger, aber die Dereferenzierungsoperationen sind typunabhängig nur nach einer expliziten Umwandlung:
void *pv = &x; int value = *(int*)pv; // OK
Kann man einen Nullzeiger (NULL) dereferenzieren?
Nein, das führt zu undefiniertem Verhalten — Speicherzerstörung oder Programmabsturz. Überprüfen Sie immer den Zeiger vor der Dereferenzierung:
int *ptr = NULL; if (ptr) { *ptr = 10; // Wird niemals ausgeführt }
Ein Entwickler nimmt die Adresse einer lokalen Variablen in einer Funktion, gibt sie zurück und dereferenziert den Zeiger im aufrufenden Code.
Vorteile:
Nachteile:
Es wird dynamisch Speicher für eine Variable zugewiesen, die Adresse wird an den aufrufenden Code zurückgegeben und am Ende wird sie über free freigegeben.
Vorteile:
Nachteile: