Hallo und willkommen zurück.
In dieser Vorlesung möchte ich über ein Konzept sprechen, das als Referenzübergabe bezeichnet wird.
Als wir zum ersten Mal über Zeiger sprachen, erwähnte ich einen der Vorteile, dass
Sie nicht so viele globale Variablen verwenden müssen.
Denn wenn Sie einen Zeiger auf eine
Funktion übergeben, können die Funktionen diesen Parameter verwenden. Wenn dieser Parameter geändert wird, werden die
Daten außerhalb der Funktion geändert.
Das ist also ein wertvolles, wertvolles Konzept.
Wir werden darüber reden. Dies ist eher ein Konzept. C setzt das eigentlich nicht ein.
Und ich werde Ihnen zeigen, wie und Ihnen einige Beispiele
geben, wie dies im Grunde funktioniert.
Es gibt also dieses Konzept der Wertübergabe. Das hat mit Funktionen zu tun.
Wir haben darüber gesprochen, Daten an eine Funktion zu übergeben, aber wie werden sie tatsächlich
in Bezug auf die Sprache im Compiler übergeben?
Es gibt also ein Konzept der Wertübergabe. Und darüber
haben wir bisher gesprochen. Immer wenn wir die Funktion
neben der scanf-Funktion aufrufen, aber jedes Mal, wenn wir die
Funktion aufrufen, wurden diese Daten innerhalb der Funktion nicht
außerhalb der Funktion geändert.
Wir haben also über lokale Variablen gesprochen, die ein anderes Konzept haben.
Wenn Sie Daten an eine Funktion übergeben, können Sie sie auf zwei Arten übergeben.
Sie können es als Wert übergeben, Sie können es als Referenz übergeben.
C geht ausschließlich nach Wert und
Java
auch nach Wert. Es simuliert jedoch die Referenzübergabe,
da Sie Adressen kopieren.
Und obwohl dieses Konzept, das
als Referenz übergeben wird, von c nicht speziell verwendet
wird, simuliert es es. Um zu verstehen, was Pass-by-Reference bedeutet
und warum das wichtig ist, werden wir darüber sprechen.
Ein Wertübergabe erfolgt jedoch, wenn eine Funktion den tatsächlichen Wert eines Arguments in
den formalen Parameter der Funktion kopiert.
Wenn Sie eine Ganzzahl, ein Gleitkomma oder ein
Double haben und diese als Argument an eine Funktion übergeben, wird
diese tatsächliche Variable außerhalb der Funktion nicht geändert, da sie kopiert wird.
Änderungen am Parameter innerhalb der Funktion haben also keine Auswirkung auf das Argument.
Das übergebene Argument wird nicht geändert.
Es verhält sich also fast wie eine lokale Variable, da es sich um eine Kopie handelt.
Wie es tatsächlich unter der Haube passiert, wird kopiert und an die Funktion übergeben.
Das C-Programm verwendet call by value, um Argumente zu übergeben.
Alles wird als Wert bezeichnet.
Diese Begriffe werden synonym verwendet.
Dies bedeutet wiederum, dass der Code innerhalb einer Funktion die zum Aufrufen der Funktion verwendeten Argumente nicht ändern kann.
Es gibt keine Änderungen an den Werten, obwohl sie innerhalb der Funktion geändert wurden.
Es scheint, als wären sie lokale Variablen.
Aus diesem Grund mussten Sie bis zu
diesem Zeitpunkt globale Daten erstellen, wenn Sie die Daten von einer Funktion zur nächsten freigeben wollten.
Und so funktioniert c.
Aber was passiert, wenn Sie tatsächlich eine Kopie
einer Adresse übergeben? Dann kann es den Durchgang als Referenz imitieren.
Aber hier ist ein Beispiel dafür, wie wir Pass-by-Value verwendet haben. Es wird hier sehr schön demonstriert.
Diese Swap-Routine ist ein häufig verwendeter Fall, um die Übergabe von Werten
zu demonstrieren, da sie eine temporäre Temperatur erzeugt und die Parameter austauscht, an
die die Argumente übergeben werden.
Wenn wir also eine Funktion namens swap haben, die zwei ganze Zahlen
akzeptiert, erstellen wir eine lokale Variable temp.
Wenn wir dem Parameter x temp zuweisen, wird temp
gleich x sein. Wenn wir sagen, dass x gleich y
ist, wird y jetzt gleich x sein. Wenn wir sagen, dass y gleich temp
ist, ist y gleich temp.
Wenn Sie diese Funktion aufrufen und diese Werte übergeben, sind
x und y für diese Funktion lokal.
Diese Variablen werden außerhalb dieser Funktion nicht geändert.
Und diese Funktion demonstriert es sehr nützlich, weil
wir y und x zuweisen.
Und x und y sind für diese Funktion lokal, da wir den
Wert übergeben, sie außerhalb dieser Funktion nicht geändert werden und deshalb globale Variablen verwendet werden müssen.
Aber sie sind ganze Zahlen. Das sind zwei ganze Zahlen x und y. Sie sind keine Adressen,
sie sind ganze Zahlen und das ist wichtig.
Wenn wir also Swap
aufrufen und sehen, wie dies aussieht, werden Sie
feststellen, dass sich die Werte nicht ändern.
Wenn wir also eine Variable namens 100 b mit 200
erstellen und die Variablen ausdrucken, bevor wir tauschen, 100 und
200, dann rufen wir swap auf,
werden die Variablen nicht geändert, nachdem
wir sie erneut ausgedruckt haben.
Schauen wir uns das also in Codeblöcken an und dies wird die Übergabe nach Wert demonstrieren.
Hier ist unser Beispiel. Wir haben unsere Tauschroutine.
Wir tauschen Werte von Daten aus, die x und y übergeben wurden.
Wir nennen es mit 100 200.
Wir werden ausdrucken, bevor wir die Funktion aufrufen.
Wir werden danach ausdrucken.
Und Sie werden feststellen, dass sich die Variablen a und b nie ändern.
Und der Grund dafür ist, dass wir den Wert weitergeben.
Wenn ich dieses Programm ausführe, können wir
sehen, dass vor dem Tauschen der Wert von a 100 war, nachdem Sie den Wert von a 100 und für
b 200 und 200 den gleichen Wert getauscht haben.
Und der Grund dafür ist, dass wir den Wert überschritten haben. Wenn wir als Referenz übergeben würden,
würden sich diese Variablen a und b nach dem Aufruf zum Tauschen ändern.
Wie wäre es nun, wenn wir dieselbe Technik verwenden, die als Wert übergeben
wird, aber Zeiger kopieren? Was wird Ihrer Meinung nach passieren?
Zeiger und Funktionen verstehen sich also recht gut.
Sie können einen Zeiger als Argument an
eine Funktion übergeben und eine Funktion kann einen Zeiger als Ergebnis zurückgeben.
Wir werden auch zeigen, wie das geht.
Durch Referenzübergabe wird jedoch die Adresse eines Arguments in den formalen Parameter kopiert.
Die Adresse wird verwendet, um auf das tatsächliche Argument zuzugreifen, das im Aufruf verwendet wird.
Dies bedeutet also, dass die Änderungen, die am Parameter innerhalb der
Funktion vorgenommen werden, sich auf das Argument auswirken, das im Aufruf enthalten ist.
Und obwohl es technisch nicht unter der Haube liegt, die als Referenz übergeben
wird, ahmt es die Referenzübergabe nach oder simuliert sie.
Wir kopieren die Adresse. Wenn Sie die Adresse kopieren,
haben Sie eine neue Adresse und Speicher für diesen Wert die Adresse.
Wenn Sie jedoch versuchen, diese Adresse zuzuweisen, wird sie der Adresse zugewiesen.
Obwohl es als Wert übergeben wird, wird es kopiert.
Und wenn Sie eine reguläre Ganzzahl kopieren, nehmen Sie keine Änderungen vor. Wenn Sie eine Adresse kopieren, befindet sich die
Adresse im Speicher. Wenn Sie also Änderungen vornehmen, werden Sie Änderungen an dieser Adresse vornehmen.
Um den Wert als Referenz
zu übergeben, werden Argumentzeiger wie bei jedem anderen Wert an die Funktionen übergeben.
Sie müssen die Funktionsparameter als Zeigertypen mit dem Sternchen deklarieren.
Änderungen innerhalb der Funktion werden auch außerhalb der Funktion wiedergegeben.
Sie müssen nicht so häufig globale Variablen verwenden.
Im Gegensatz zu einem Aufruf nach Wert, bei dem die Änderungen nicht außerhalb der Funktion angezeigt werden.
Wir kopieren immer noch. Wir übergeben immer noch den Wert. Es ist nur der Wert einer Kopie der Adresse.
Das ist also ein wichtiges Konzept, um es zu verstehen.
Wenn wir nun unsere Swap-Funktion erstellen,
erstellen wir sie mit der Deklaration innerhalb der Funktion
als Sternchen, Stern und Stern.
Das heißt, dass diese Funktion Zeiger nimmt.
Wenn wir nun innerhalb dieser Funktion zuweisen, müssen
wir den Indirektionsoperator tatsächlich zur Dereferenzierung verwenden, da wir
die Werte zuweisen möchten. Wir werden den Wert zuweisen, dass
das x, das x auf die Temperatur zeigt.
Wir werden den Wert von x Punkten dem Wert zuweisen, auf
den y zeigt, und dann werden wir den Wert, auf den y zeigt, temp zuweisen.
Temp ist eine ganze Zahl, daher müssen wir sie nicht dereferenzieren.
Wenn wir es
nun mit a100 und b200 durch Übergabe
von a und b aufrufen, sind a und b keine Zeiger, daher müssen wir
die Adresse übergeben, da die Funktion Zeiger akzeptiert.
Wenn Sie eine Funktion haben, die Zeiger akzeptiert und keinen Zeiger deklariert,
müssen Sie die Adresse des Operators verwenden. Dies entspricht der Verwendung von scanf.
Aber jetzt werden Sie feststellen, wenn wir dies
nach dem Aufruf aufrufen, um die Variablen a und b auszutauschen. Sie
werden geändert, sie werden ausgetauscht. A wird 200 sein, b wird 100 sein.
Schauen wir uns nun dieses Beispiel mit unserer Änderung der Swap-Methode in Zeiger in Codeblöcken an.
Wir sind in Codeblöcken. Wir haben die Swap-Funktion geändert, um Zeiger aufzunehmen.
Wir müssen sie also dereferenzieren, wenn wir sie zuweisen.
Wir übergeben jetzt auch die Adressen von a und b, da diese jetzt ganze Zahlen
sind und der Swap jetzt Zeiger nimmt. Wenn wir dies ausführen, werden wir
sehen, dass der Anruf und danach jetzt geändert werden.
Bevor wir also Swap aufrufen, ist a gleich 100, nachdem wir Swap aufgerufen haben, ist 200.
Bevor wir Swap für b nennen, ist es 200. Danach ist es 100.
Wir können also die Werte von Variablen innerhalb der Funktion ändern,
da wir eine Kopie der Adresse erstellen. Sehr, sehr wichtig und einer der
großen Vorteile von Zeigern.
Fassen wir also die Syntax zusammen. Ich habe es bereits getan, aber lassen Sie uns genauer darauf eingehen.
Sie können einer Funktion zwei Arten von Informationen über eine Variable übermitteln.
Sie können den Wert von x
übertragen und die Funktion muss mit demselben Typ wie x deklariert werden.
Wir wissen das. Immer wenn wir Daten
an eine Funktion übergeben, müssen wir beim Aufrufen dieselben Typen haben.
Und hier haben wir int function1, um es aufzurufen, und es ist als int num definiert.
Wenn wir also den Wert von x in der Funktion übertragen, müssen sie mit demselben Typ deklariert werden.
Wenn Sie dann tatsächlich eine Adresse von x aufrufen möchten,
muss die Funktionsdefinition einen Zeiger auf den richtigen Typ enthalten.
Wenn Sie also Zeiger verwenden, müssen Sie sicherstellen, dass Sie die
Adresse abrufen müssen, wenn Sie Daten übergeben und diese Daten kein Zeiger sind.
Zusammenfassend lässt sich sagen, dass Sie, wenn Sie eine Funktion definieren, die keinen Zeiger akzeptiert,
diese einfach aufrufen und die Daten übergeben können.
Stellen Sie sicher, dass es kein Zeiger ist.
Wenn Sie eine Funktion haben, die einen Sternchenzeiger verwendet,
müssen Sie sie
beim Aufrufen mit dem Operator add oder sub aufrufen.
Sie müssen die Adresse übergeben.
Das ist die Syntax.
Jetzt können Sie einen Funktionsparameter auch mit dem Schlüsselwort Konstante qualifizieren.
Dies zeigt an, dass die Funktion das für diesen Parameter übergebene Argument als Konstante behandelt.
Dies ist nur nützlich, wenn der Parameter ein Zeiger ist.
Denn wenn Sie einen Wert übergeben und keine Zeiger übergeben, spielt dies keine Rolle, da sich dies
nicht auf die Änderung außerhalb der Funktion auswirkt. Warum sollten Sie
sie also zu einer Konstanten machen, wen interessiert es, wenn Sie sie ändern .
Der einzige Grund, warum Sie eine Zeigerkonstante festlegen, besteht darin, dass Sie nicht
möchten, dass sich die Funktionswerte außerhalb ändern.
Sie können also das Schlüsselwort constant auf einen Parameter anwenden, der ein Zeiger
ist, um anzugeben, dass die Funktion den Wert, auf den das Argument verweist, nicht ändert.
Sehr wichtig.
In diesem Beispiel haben wir also eine Funktion zum Senden von Nachrichten. Es wird ein
p-Nachrichtenzeiger benötigt.
Wir setzen das konstante Schlüsselwort vor den Zeichenstern.
Diese Art von Parameter p-Nachricht ist also ein Zeiger auf ein konstantes Zeichen.
Es ist der Zeichenwert, der konstant ist, nicht seine Adresse.
In diesem Fall kann sich also der Zeiger, auf den gezeigt wird, nicht ändern.
Wir können die Adresse ändern, aber wir können nicht ändern, was auf den Wert zeigt.
Die Syntax ähnelt der beim Erstellen von Konstanten für andere Zeiger.
Das konstante Schlüsselwort ist das erste, was angezeigt wird, dann können Sie den Wert nicht ändern.
Jetzt können Sie angeben, dass der Zeiger selbst konstant ist.
Dies ist jedoch wenig sinnvoll, da die Adresse als Wert übergeben wird.
Sie können den Renderzeiger
in der aufrufenden Funktion nicht ändern. Dies ist nur dann der Fall, wenn Sie versuchen, die Adresse so zu ändern, dass sie
nicht geändert werden kann. Worum geht es, weil sie als Wert übergeben wird? Sie erstellen also
tatsächlich einen neuen Speicherort
für diese bestimmte Adresse. Also, wenn Sie es ändern, wen interessiert es, dass es es nicht von außen ändern wird.
Sie möchten nur in der Lage sein, den Parameter
zu einer Konstanten zu machen, damit Sie den Wert dessen, auf den er zeigt,
nicht ändern. Sie können
den ursprünglichen Zeiger und die aufrufende Funktion sowieso nicht ändern, da er als Wert
übergeben wird, der von copy übergeben wird.
Der Compiler weiß, dass ein Argument, das ein Zeiger auf konstante Daten
ist, sicher ist. Dies hat also Vorteile. Sie können nicht versehentlich ändern, auf was der Wert zeigt.
Sie können dies also erneut tun, wenn Sie nicht möchten, dass die Änderungen außerhalb der Funktion angezeigt werden.
Wenn Sie einen Zeiger auf konstante Daten als Argument für einen
Parameter übergeben, muss der Parameter wie oben verwendet werden.
Wenn Sie die Funktion aufrufen und an eine Konstante übergeben,
muss die Funktionsdeklaration ebenso wie normale andere Zeiger, die Konstanten sind,
auch einen konstanten Zeichenzeiger verwenden.
Sie müssen definiert werden und die Definitionen müssen mit dem Prototyp übereinstimmen.
Rückgabe von Zeigern von einer Funktion.
Das Zurückgeben eines Zeigers von einer Funktion ist eine besonders leistungsstarke Funktion.
Auf diese Weise können Sie nicht nur einen einzelnen Wert, sondern eine ganze Reihe von Werten zurückgeben.
Einer der anderen Vorteile, die ich bei Zeigern erwähnt
habe, ist, dass Sie jetzt mehr Daten von einer Funktion zurückgeben können.
In der Vergangenheit können Sie nur einen Wert zurückgeben.
Aber mit einem Zeiger, weil ein Zeiger auf eine
Struktur verweisen könnte, über die wir noch nicht gesprochen haben, oder auf andere Dinge,
bei denen Sie mehrere Werte
zurückgeben können. Wir wissen also, wie Zeiger an Funktionen übergeben werden. Jetzt möchten
wir über das Zurückgeben von Zeigern sprechen.
Sie müssten eine Funktion deklarieren, die einen Zeiger zurückgibt. Die Funktionsdeklaration muss also übereinstimmen.
Das ist sehr einfach. Sie sagen einfach, verwenden Sie das Sternchen,
wenn Sie die Funktion deklarieren oder definieren und den Rückgabetyp für diesen Zeiger haben, auf den er zeigt.
Seien Sie also vorsichtig, obwohl die Rückgabe eines Zeigers besondere Gefahren birgt.
Verwenden Sie lokale Variablen, um eine Störung der Variablen zu vermeiden, auf die das Argument verweist.
Es ist etwas problematisch, wenn Sie Zeiger zurückgeben, denn wenn Sie diesen Zeiger innerhalb der
Funktion ändern und dann zurückgeben, kann
dies etwas sein, das Sie nicht beabsichtigen.
Verwenden Sie daher immer lokale Variablen, wenn Sie eine Variable, auf die Ihr
Argument verweist, nicht beeinflussen möchten.
In dieser Vorlesung wurde beschrieben,
wie Sie Zeiger an
Funktionen übergeben und Zeiger von Funktionen zurückgeben können.
Durch die Verwendung dieser Mechanismen zum Übergeben von Zeigern
an eine Funktion wird die Übergabe als Referenz demonstriert oder
nachgeahmt, da Sie in eine Adresse kopieren.
Und wenn Sie eine Adresse kopieren, wenn Sie an diese Adresse schreiben,
aktualisieren Sie alles, was auf
diese Adresse zeigt. Dies bedeutet effektiv, dass Sie den Wert der
Daten innerhalb der Funktion ändern, der außerhalb der Funktion wiedergegeben wird.
Wir verwenden die Swap-Routine, um dies zu demonstrieren.
Dies ist ein sehr leistungsfähiges Konzept. Und wenn Sie die Referenzübergabe imitieren möchten,
können Sie dazu Zeiger verwenden, und Sie möchten dies tun, wenn Sie Dinge außerhalb der Funktion ändern möchten.
Vielen Dank.