Warum C-Zeiger wichtig sind: Wie Pass-by-Pointer die Änderung realer Daten ermöglicht

7

Die meisten Entwickler begegnen Zeigern in C über einen speziellen Mechanismus, der als Pass-by-Pointer bekannt ist. Es ist nicht nur eine Syntax-Eigenart; Dies ist der grundlegende Grund, warum Funktionen den externen Zustand ändern können. Sie haben das wahrscheinlich schon einmal gesehen, ohne es zu merken. Betrachten Sie die Funktion „scanf“. Jedes Mal, wenn Sie „scanf“ aufrufen, müssen Sie Ihren Variablen den Adressenoperator („&“) voranstellen.

scanf("%d", &myNumber);

Wenn Sie dieses kaufmännische Und weglassen, stürzt das Programm ab. Warum? Denn „scanf“ erwartet eine Speicheradresse, keinen Wert. Das Verständnis dieses Verhaltens entschlüsselt die Logik hinter wie C mit Funktionsparametern umgeht. Wenn Sie einen Zeiger übergeben, erteilen Sie einer Funktion die Berechtigung, auf Ihren Speicher zuzugreifen und Daten direkt neu zu schreiben.

Das Scheitern von Pass-by-Value

Um zu verstehen, warum Zeiger notwendig sind, müssen wir uns ansehen, was passiert, wenn sie fehlen. Ein häufiger Anfängerfehler ist der Versuch, eine „Swap“-Funktion zu schreiben, die zwei ganzzahlige Werte austauscht.

Hier ist eine naive Implementierung, die fehlschlägt:

„c

void swap(int i, int j) {
int t;
t = ich;
ich = j;
j = t;
}

void main() {
int a, b;
a = 5;
b = 10;
printf(“%d %d\n”, a, b);
swap(a, b);
printf(“%d %d\n”, a, b);
}

Führen Sie diesen Code aus. Die Ausgabe zeigt „5 10“, gefolgt von „5 10“. Der Tausch fand nicht statt.

Der Grund ist einfach. In C werden Argumente standardmäßig nach Wert übergeben. Wenn „swap(a, b)“ aufgerufen wird, erstellt das System lokale Kopien von „a“ und „b“ mit den Namen „i“ und „j“. Die Funktion vertauscht die Werte von „i“ und „j“ perfekt. Aber wenn die Funktion zurückkehrt, werden diese lokalen Variablen zerstört. Das ursprüngliche „a“ und „b“ in „main“ bleiben unberührt.

Die Lösung: Pass-by-Pointer

Um die ursprünglichen Variablen zu ändern, benötigt die Funktion Zugriff auf ihre tatsächlichen Speicherorte, nicht auf Kopien ihrer Werte. Hier werden Zeiger für Funktionsparameter unerlässlich.

Hier ist die korrigierte Implementierung:

„c

void swap(int i, int j) {
int t;
t = i;
i = j;
j = t;
}

void main() {
int a, b;
a = 5;
b = 10;
printf(“%d %d\n”, a, b);
swap(&a, &b);
printf(“%d %d\n”, a, b);
}

Die Ausgabe lautet nun „5 10“, gefolgt von „10 5“. Der Tausch hat funktioniert.

So funktioniert die Zeiger-Dereferenzierung

Der Unterschied liegt darin, was an die Funktion übergeben wird.

  1. Der Aufruf: „swap(&a, &b)“ übergibt die Adressen von „a“ und „b“.
  2. Die Parameter: Die Funktionssignatur „void swap(int i, int j)“ deklariert „i“ und „j“ als Zeiger auf ganze Zahlen.
  3. Die Verbindung: Innerhalb von „swap“ enthält „i“ die Adresse von „a“. „j“ enthält die Adresse von „b“.
  4. Die Dereferenzierung: Die Anweisung „i = j“ bedeutet „gehen Sie zu der in „i“ gespeicherten Speicheradresse und schreiben Sie den an der in „j“ gespeicherten Speicheradresse gefundenen Wert hinein.“

Stellen Sie sich visuell zwei Kästchen mit der Bezeichnung „a“ und „b“ vor.
– „a“ enthält „5“.
– „b“ enthält „10“.
– „i“ ist ein Zettel, auf dem die Adresse von Feld „a“ steht.
– „j“ ist ein Zettel, auf dem die Adresse von Feld „b“ steht.

Wenn der Code „t = i“ ausführt, liest er die Notiz „i“, geht zu dieser Stelle und liest den Wert „5“. Es speichert „5“ in „t“. Dann liest „ i = *j“ den Wert aus Box „b“ (das ist „10“) und schreibt ihn zurück in Box „a“. Die Originalkartons haben sich geändert.

Die Gefahr, die Adresse zu verpassen