Wenn C die Übergabe einer Variablen als Referenz nicht unterstützt, warum funktioniert dies?
#include <stdio.h>
void f(int *j) {
(*j)++;
}
int main() {
int i = 20;
int *p = &i;
f(p);
printf("i = %d\n", i);
return 0;
}
Ausgabe:
$ gcc -std=c99 test.c
$ a.exe
i = 21
&
vor dem Aufrufen der Funktion explizit eine Referenz (mit ) erstellen und diese explizit (mit*
) in der Funktion dereferenzieren .f(&i);
eine Implementierung von Referenzübergabe ist, die nicht nur in C existiert. C ReferenzübergabeAntworten:
Weil Sie den Wert des Zeigers an die Methode übergeben und ihn dann dereferenzieren, um die Ganzzahl zu erhalten, auf die verwiesen wird.
quelle
func
:func(&A);
Dies würde einen Zeiger auf A an die Funktion übergeben, ohne etwas zu kopieren. Es handelt sich um eine Wertübergabe, aber dieser Wert ist eine Referenz, sodass Sie die Variable A als Referenz übergeben. Kein Kopieren erforderlich. Es ist gültig zu sagen, dass es sich um eine Referenz handelt.Dies ist keine Referenzübergabe, sondern eine Wertübergabe, wie andere angegeben haben.
Die Regel lautet wie folgt:
Versuchen wir, die Unterschiede zwischen Skalar- und Zeigerparametern einer Funktion zu erkennen.
Skalare Variablen
Dieses kurze Programm zeigt die Wertübergabe mithilfe einer skalaren Variablen.
param
wird als formaler Parameter bezeichnet undvariable
beim Aufrufen der Funktion als tatsächlicher Parameter. Hinweis Inkrementierungparam
in der Funktion ändert sich nichtvariable
.Das Ergebnis ist
Illusion von Referenzübergabe
Wir ändern den Code leicht.
param
ist jetzt ein Zeiger.Das Ergebnis ist
Das lässt Sie glauben, dass der Parameter als Referenz übergeben wurde. Es war nicht. Es wurde als Wert übergeben, wobei der Parameterwert eine Adresse ist. Der Wert vom Typ int wurde inkrementiert, und dies ist der Nebeneffekt, der uns glauben lässt, dass es sich um einen Funktionsaufruf mit Referenzübergabe handelt.
Zeiger - Wertübergabe
Wie können wir diese Tatsache zeigen / beweisen? Nun, vielleicht können wir das erste Beispiel für skalare Variablen ausprobieren, aber anstelle von skalar verwenden wir Adressen (Zeiger). Mal sehen, ob das helfen kann.
Das Ergebnis ist, dass die beiden Adressen gleich sind (machen Sie sich keine Sorgen über den genauen Wert).
Beispielergebnis:
Meiner Meinung nach beweist dies deutlich, dass Zeiger wertmäßig übergeben werden. Andernfalls
ptr
wäreNULL
nach Funktionsaufruf.quelle
Quelle: www-cs-students.stanford.edu
quelle
Weil der obige Code keine Referenz enthält. Die Verwendung von Zeigern (z. B.
void func(int* p)
) erfolgt nach Adresse. Dies ist eine Referenz in C ++ (funktioniert in C nicht):quelle
Ihr Beispiel funktioniert, weil Sie die Adresse Ihrer Variablen an eine Funktion übergeben, die ihren Wert mit dem Dereferenzierungsoperator bearbeitet .
Obwohl C keine Referenzdatentypen unterstützt , können Sie die Referenzübergabe simulieren, indem Sie wie in Ihrem Beispiel explizit Zeigerwerte übergeben.
Der C ++ - Referenzdatentyp ist weniger leistungsfähig, wird jedoch als sicherer angesehen als der von C geerbte Zeigertyp. Dies wäre Ihr Beispiel, angepasst an die Verwendung von C ++ - Referenzen :
quelle
Sie übergeben einen Zeiger (Adressposition) nach Wert .
Es ist wie zu sagen: "Hier ist der Ort mit den Daten, die Sie aktualisieren sollen."
quelle
p ist eine Zeigervariable. Sein Wert ist die Adresse von i. Wenn Sie f aufrufen, übergeben Sie den Wert von p, der die Adresse von i ist.
quelle
Keine Referenzübergabe in C, aber p "bezieht" sich auf i, und Sie übergeben p als Wert.
quelle
In C ist alles Wertübergabe. Die Verwendung von Zeigern gibt uns die Illusion, dass wir als Referenz übergeben, weil sich der Wert der Variablen ändert. Wenn Sie jedoch die Adresse der Zeigervariablen ausdrucken, werden Sie feststellen, dass sie nicht betroffen ist. Eine Kopie des Wertes der Adresse ist in gebenen an die Funktion. Unten sehen Sie einen Ausschnitt, der dies veranschaulicht.
quelle
Weil Sie einen Zeiger (Speicheradresse) auf die Variable p in die Funktion f übergeben. Mit anderen Worten, Sie übergeben einen Zeiger, keine Referenz.
quelle
Kurze Antwort: Ja, C implementiert die Parameterübergabe als Referenz mithilfe von Zeigern.
Bei der Implementierung der Parameterübergabe verwenden Entwickler von Programmiersprachen drei verschiedene Strategien (oder semantische Modelle): Daten in das Unterprogramm übertragen, Daten aus dem Unterprogramm empfangen oder beides. Diese Modelle sind allgemein als In-Modus, Out-Modus und Inout-Modus entsprechend bekannt.
Von Sprachdesignern wurden mehrere Modelle entwickelt, um diese drei Strategien zur Übergabe elementarer Parameter zu implementieren:
Pass-by-Value (Semantik im Modus) Pass-by-Result (Semantik im Out-Modus) Pass-by-Value-Ergebnis (Semantik im Inout-Modus) Pass-by-Reference (Semantik im Inout-Modus) Pass-by-Name (Inout-Modus) Semantik)
Pass-by-Reference ist die zweite Technik zum Übergeben von Parametern im Inout-Modus. Anstatt Daten zwischen der Hauptroutine und dem Unterprogramm hin und her zu kopieren, sendet das Laufzeitsystem einen direkten Zugriffspfad auf die Daten für das Unterprogramm. Bei dieser Strategie hat das Unterprogramm direkten Zugriff auf die Daten, wobei die Daten effektiv mit der Hauptroutine geteilt werden. Der Hauptvorteil dieser Technik besteht darin, dass sie zeitlich und räumlich absolut effizient ist, da kein Speicherplatz dupliziert werden muss und keine Datenkopiervorgänge erforderlich sind.
Die Implementierung der Parameterübergabe in C: C implementiert die Semantik der Wertübergabe und der Referenzübergabe (Inout-Modus) unter Verwendung von Zeigern als Parameter. Der Zeiger wird an das Unterprogramm gesendet und es werden überhaupt keine tatsächlichen Daten kopiert. Da ein Zeiger jedoch ein Zugriffspfad auf die Daten der Hauptroutine ist, kann das Unterprogramm die Daten in der Hauptroutine ändern. C hat diese Methode von ALGOL68 übernommen.
Implementierung der Parameterübergabe in C ++: C ++ implementiert auch die Semantik der Referenzübergabe (Inout-Modus) mithilfe von Zeigern und einer speziellen Art von Zeigern, die als Referenztyp bezeichnet wird. Referenztypzeiger werden implizit innerhalb des Unterprogramms dereferenziert, aber ihre Semantik wird auch als Referenz übergeben.
Das Schlüsselkonzept hier ist also, dass die Referenzübergabe einen Zugriffspfad auf die Daten implementiert, anstatt die Daten in das Unterprogramm zu kopieren. Datenzugriffspfade können explizit dereferenzierte Zeiger oder automatisch dereferenzierte Zeiger (Referenztyp) sein.
Weitere Informationen finden Sie im Buch Concepts of Programming Languages von Robert Sebesta, 10. Aufl., Kapitel 9.
quelle
Sie übergeben kein int als Referenz, sondern einen Zeiger auf ein int als Wert. Unterschiedliche Syntax, gleiche Bedeutung.
quelle
void func(int* ptr){ *ptr=111; int newValue=500; ptr = &newvalue }
mit aufrufenint main(){ int value=0; func(&value); printf("%i\n",value); return 0; }
, wird 111 anstelle von 500 ausgegeben. Wenn Sie als Referenz übergeben, sollte 500 ausgegeben werden. C unterstützt die Übergabe von Parametern als Referenz nicht.ptr = &newvalue
nicht zugelassen. Unabhängig vom Unterschied denke ich, dass Sie darauf hinweisen, dass "gleiche Bedeutung" nicht genau wahr ist, weil Sie auch zusätzliche Funktionen in C haben (die Möglichkeit, die "Referenz" selbst neu zuzuweisen).ptr=&newvalue
wenn es als Referenz übergeben wird. Stattdessen schreiben wirptr=newvalue
Hier ist ein Beispiel in C ++:void func(int& ptr){ ptr=111; int newValue=500; ptr = newValue; }
Der Wert des an func () übergebenen Parameters wird500
.param = new Class()
innerhalb einer Funktion keine Auswirkung auf den Aufrufer hat, wenn sie als Wert (Zeiger) übergeben wird. Wennparam
als Referenz übergeben wird, sind die Änderungen für den Anrufer sichtbar.In C verwenden Sie zum Übergeben als Referenz den Operator "Adresse von",
&
der für eine Variable verwendet werden soll. In Ihrem Fallp
müssen Sie dem Operator "Adresse von" jedoch kein Präfix voranstellen , da Sie die Zeigervariable verwendet haben . Es wäre wahr gewesen, wenn Sie&i
als Parameter verwendet hätten :f(&i)
.Sie können dies auch hinzufügen, um zu dereferenzieren
p
und zu sehen, wie dieser Wert übereinstimmti
:quelle
Zeiger und Referenzen sind zwei verschiedene Thigngs.
Ein paar Dinge, die ich nicht erwähnt habe.
Ein Zeiger ist die Adresse von etwas. Ein Zeiger kann wie jede andere Variable gespeichert und kopiert werden. Es hat also eine Größe.
Eine Referenz sollte als ALIAS von etwas angesehen werden. Es hat keine Größe und kann nicht gespeichert werden. Es muss sich auf etwas beziehen, dh. es kann nicht null sein oder geändert werden. Nun, manchmal muss der Compiler die Referenz als Zeiger speichern, aber das ist ein Implementierungsdetail.
Bei Referenzen treten keine Probleme mit Zeigern auf, wie z. B. die Behandlung von Eigentumsrechten, die Nullprüfung und die De-Referenzierung bei Verwendung.
quelle
'Als Referenz übergeben' (mithilfe von Zeigern) war von Anfang an in C. Warum denkst du, ist es nicht?
quelle
j
( nicht*j
) inf()
hat keine Auswirkung aufi
inmain()
.Ich denke, C unterstützt tatsächlich die Referenzübergabe.
Die meisten Sprachen erfordern syntaktischen Zucker als Referenz anstelle von Wert. (C ++ erfordert zum Beispiel & in der Parameterdeklaration).
C benötigt dafür auch syntaktischen Zucker. Es ist * in der Parametertypdeklaration und & im Argument. Also * und & ist die C-Syntax für die Referenzübergabe.
Man könnte nun argumentieren, dass eine echte Referenzübergabe nur eine Syntax für die Parameterdeklaration erfordern sollte, nicht für die Argumentationsseite.
Aber jetzt kommt C # , das tut Unterstützung durch Bezugnahme Gang und erfordert syntaktischen Zucker auf beiden Parameter und Argumente Seiten.
Das Argument, dass C keine By-Ref-Übergabe hat, führt dazu, dass die syntaktischen Elemente, die es ausdrücken, die zugrunde liegende technische Implementierung aufweisen, überhaupt kein Argument, da dies mehr oder weniger für alle Implementierungen gilt.
Das einzige verbleibende Argument ist, dass das Übergeben von ref in C kein monolithisches Merkmal ist, sondern zwei vorhandene Merkmale kombiniert. (Nehmen Sie ref of argument by &, erwarten Sie, dass ref by * eingibt.) Für C # sind beispielsweise zwei syntaktische Elemente erforderlich, die jedoch nicht ohne einander verwendet werden können.
Dies ist offensichtlich ein gefährliches Argument, da viele andere Funktionen in Sprachen aus anderen Funktionen bestehen. (wie String-Unterstützung in C ++)
quelle
Was Sie tun, ist Wert übergeben, nicht als Referenz übergeben. Weil Sie den Wert einer Variablen 'p' an die Funktion 'f' senden (hauptsächlich als f (p);)
Das gleiche Programm in C mit Referenzübergabe sieht aus wie (!!! Dieses Programm gibt 2 Fehler aus, da Referenzübergabe in C nicht unterstützt wird.)
Ausgabe:-
quelle