C++

Verwendung von C++-Zeigern

Verwendung von C++-Zeigern
Der Speicher eines Computers besteht aus einer langen Reihe von Zellen. Die Größe jeder Zelle wird als Byte bezeichnet. Ein Byte ist ein Platz, der von einem englischen Zeichen des Alphabets eingenommen wird. Ein Objekt im gewöhnlichen Sinne ist ein aufeinanderfolgender Satz von Bytes im Speicher. Jede Zelle hat eine Adresse, die eine ganze Zahl ist, die normalerweise in hexadezimaler Form geschrieben wird. Es gibt drei Möglichkeiten, auf ein Objekt im Speicher zuzugreifen. Auf ein Objekt kann mit einem sogenannten Pointer zugegriffen werden. Der Zugriff erfolgt über eine sogenannte Referenz. Es kann weiterhin mit einer Kennung darauf zugegriffen werden. Der Fokus dieses Artikels liegt auf der Verwendung von Zeigern und Referenzen. In C++ gibt es das Pointer-Objekt und das Pointer-Objekt. Das spitze Objekt hat das Objekt von Interesse. Das Pointer-Objekt hat die Adresse des Pointer-Objekts.

Sie müssen über Grundkenntnisse in C++ verfügen, einschließlich seiner Bezeichner, Funktionen und Arrays. um diesen Artikel zu verstehen.

Das Pointer-Objekt und das Pointer-Objekt haben jeweils ihren Bezeichner.

Die Adresse des Operators &

Dies ist ein unärer Operator. Wenn ein Bezeichner folgt, wird die Adresse des Objekts des Bezeichners zurückgegeben returns. Betrachten Sie die folgende Erklärung:

int ptdInt;

Unten ist der Code, der folgende Ausdruck, gibt die durch ptdInt identifizierte Adresse zurück:

&ptdInt

Sie müssen die genaue Adresse (Nummer) beim Codieren nicht kennen.

Der Indirektionsoperator, *

Dies ist ein unärer Operator im Kontext von Zeigern. Es wird normalerweise vor einem Bezeichner eingegeben. Bei Verwendung in einer Deklaration des Bezeichners ist der Bezeichner das Zeigerobjekt, das nur die Adresse des angegebenen Objekts enthält. Wenn es vor dem Objektbezeichner des Zeigers verwendet wird, um etwas zurückzugeben, ist das zurückgegebene Ding der Wert des Objekts, auf das verwiesen wird.

Einen Zeiger erstellen

Sehen Sie sich das folgende Codesegment an:

float ptdFloat;
float *ptrFloat;
ptrFoat = &ptdFloat;

Das Segment beginnt mit der Deklaration des spitzen Objekts, ptdFloat. ptdFloat ist ein Bezeichner, der nur ein Float-Objekt identifiziert. Es könnte ein tatsächliches Objekt (Wert) zugewiesen worden sein, aber in diesem Fall wurde ihm nichts zugewiesen. Als nächstes im Segment gibt es die Deklaration des Zeigerobjekts. Der Indirektionsoperator vor diesem Bezeichner bedeutet, dass er die Adresse eines spitzen Objekts enthalten muss. Der Objekttyp float am Anfang der Anweisung bedeutet, dass das gezeigte Objekt ein Float ist. Das Pointer-Objekt ist immer vom gleichen Typ wie das Pointer-Objekt. ptrFoat ist ein Bezeichner, der nur ein Zeigerobjekt identifiziert.

In der letzten Anweisung des Codes wird die Adresse des Pointer-Objekts dem Pointer-Objekt zugewiesen. Beachten Sie die Verwendung des Adressoperators &.

Die letzte Anweisung (Zeile) oben zeigt, dass Sie nach der Deklaration des Zeigerobjekts ohne Initialisierung den Indirektionsoperator nicht benötigen, wenn Sie ihn initialisieren müssen. Tatsächlich ist es ein Syntaxfehler, den Indirektionsoperator in der dritten (letzten) Zeile zu verwenden.

Das Pointer-Objekt kann vom Pointer-Objekt in einer Anweisung wie folgt deklariert und initialisiert werden:

float ptdFloat;
float *ptrFoat = &ptdFloat;

Die erste Zeile des vorherigen Codesegments und dieses sind gleich. Die zweite und dritte Zeile des vorherigen Codesegments wurden hier zu einer Anweisung zusammengefasst.

Beachten Sie im obigen Code, dass beim Deklarieren und Initialisieren des Zeigerobjekts der Indirektionsoperator verwendet werden muss. Es wird jedoch nicht verwendet, wenn die Initialisierung danach erfolgen soll. Das Pointer-Objekt wird mit der Adresse des Pointer-Objekts initialisiert.

Im folgenden Codesegment wird der Indirektionsoperator verwendet, um den Inhalt des angezeigten Objekts zurückzugeben.

int ptdInt = 5;
int *ptrInt = &ptdInt;
cout << *ptrInt << '\n';

Die Ausgabe ist 5.

In der letzten Anweisung hier wurde der Indirektionsoperator verwendet, um den Wert zurückzugeben, auf den der Zeigerbezeichner zeigt. Bei Verwendung in einer Deklaration würde der Bezeichner für den Indirektionsoperator also die Adresse des Objekts enthalten, auf das verwiesen wird. Bei Verwendung in einem Rückgabeausdruck in Kombination mit dem Zeigerbezeichner gibt der Indirektionsoperator den Wert des angegebenen Objekts zurück.

Einem Zeiger Null zuweisen

Das Pointer-Objekt sollte immer den Typ des Pointer-Objekts haben. Bei der Deklaration des Pointer-Objekts muss der Datentyp des Pointer-Objekts verwendet werden. Dem Zeiger kann jedoch der Wert der dezimalen Null wie im folgenden Codesegment zugewiesen werden:

int ptdInt = 5;
int *ptrInt;
ptrInt = 0;
oder im Segment,
int ptdInt = 5;
int *ptrInt = 0;

In beiden Fällen wird der Zeiger (Bezeichner) als Nullzeiger bezeichnet; Das heißt, es zeigt ins Nichts. Das heißt, es hat nicht die Adresse eines spitzen Objekts. Hier ist 0 dezimal null und nicht hexadezimal null. Hexadezimale Null würde auf die erste Adresse des Computerspeichers zeigen.

Versuchen Sie nicht, den Wert zu erhalten, auf den ein Nullzeiger zeigt. Wenn Sie das versuchen, wird das Programm möglicherweise kompiliert, aber möglicherweise nicht ausgeführt.

Array-Name als konstanter Zeiger

Betrachten Sie das folgende Array:

int arr[] = 000, 100, 200, 300, 400;

Der Name des Arrays, arr ist eigentlich der Bezeichner, der die Adresse des ersten Elements des Arrays hat. Der folgende Ausdruck gibt den ersten Wert im Array zurück:

*arr

Beim Array, dem Inkrementoperator, verhält sich ++ anders. Anstatt 1 hinzuzufügen, ersetzt es die Adresse des Zeigers durch die Adresse des nächsten Elements im Array. Der Name des Arrays ist jedoch ein konstanter Zeiger; d.h. sein Inhalt (Adresse) kann nicht geändert oder erhöht werden. Zum Inkrementieren muss die Startadresse des Arrays also wie folgt einem nicht konstanten Zeiger zugewiesen werden:

int *ptr = arr;

Jetzt kann ptr inkrementiert werden, um auf das nächste Element des Arrays zu zeigen. ptr wurde hier als Zeigerobjekt deklariert. Ohne * hier wäre es kein Zeiger; es wäre ein Bezeichner, um ein int-Objekt zu halten und keine Speicheradresse zu halten.

Das folgende Codesegment zeigt schließlich auf das vierte Element:

++ptr;
++ptr;
++ptr;

Der folgende Code gibt den vierten Wert des Arrays aus:

int arr[] = 000, 100, 200, 300, 400;
int *ptr = arr;
++ptr;
++ptr;
++ptr;
cout << *ptr << '\n';

Der Ausgang ist 300.

Funktionsname als Bezeichner

Der Name einer Funktion ist der Bezeichner der Funktion. Betrachten Sie die folgende Funktionsdefinition:

int fn()

cout << "seen" << '\n';
Rückkehr 4;

fn ist der Bezeichner der Funktion. Der Ausdruck,

&fn

gibt die Adresse der Funktion im Speicher zurück. fn ist wie das spitze Objekt. Die folgende Deklaration deklariert einen Zeiger auf eine Funktion:

int (*funktion)();

Der Bezeichner für das gezeigte Objekt und der Bezeichner für das Zeigerobjekt ist unterschiedlich. func ist ein Zeiger auf eine Funktion. fn ist der Bezeichner einer Funktion. Und so kann func wie folgt auf fn zeigen:

Funktion = &fn;

Der Wert (Inhalt) von func ist die Adresse von fn. Die beiden Bezeichner könnten wie folgt mit einer Initialisierungsanweisung verknüpft worden sein:

int (*funktion)() = &fn;

Beachten Sie die Unterschiede und Gemeinsamkeiten beim Umgang mit Funktionszeigern und Skalarzeigern. func ist ein Zeiger auf eine Funktion; es ist das spitze Objekt; es wird anders als ein Skalarzeiger deklariert.

Die Funktion kann aufgerufen werden mit,

fn()
oder
func()

Es kann nicht mit *func() aufgerufen werden.

Wenn die Funktion Parameter hat, enthalten die zweiten Klammern die Typen der Parameter und müssen nicht die Bezeichner für die Parameter enthalten. Das folgende Programm veranschaulicht dies:

#einschließen
Verwenden von Namespace-Std;
float fn (float fl, int in)

Rückkehr fl;

int main()

float (*func)(float, int) = &fn;
Schwimmerwert = func(2.5, 6);
cout << val << '\n';
0 zurückgeben;

Die Ausgabe ist 2.5.

C++-Referenz

Die Referenzierung in C++ ist nur eine Möglichkeit, ein Synonym (einen anderen Namen) für einen Bezeichner zu erzeugen. Es verwendet den &-Operator, aber nicht auf die gleiche Weise wie & für Zeiger verwendet wird. Betrachten Sie das folgende Codesegment:

int myInt = 8;
int &yourInt = myInt;
cout << myInt << '\n';
cout << yourInt << '\n';

Die Ausgabe ist:

8
8

Die erste Anweisung initialisiert den Bezeichner myInt; ich.e. myInt wird deklariert und hält den Wert 8. Die zweite Anweisung macht einen neuen Bezeichner, yourInt zu einem Synonym für myInt. Dazu wird in der Deklaration der Operator & zwischen dem Datentyp und dem neuen Bezeichner platziert. Die cout-Anweisungen zeigen, dass die beiden Bezeichner Synonyme sind. Um den Wert in diesem Fall zurückzugeben, müssen Sie ihm kein * voranstellen . Verwenden Sie einfach die Kennung.

myInt und yourInt sind hier keine zwei verschiedenen Objekte. Sie sind zwei verschiedene Bezeichner, die auf denselben Speicherort mit dem Wert 8 value verweisen (identifizieren). Wenn der Wert von myInt geändert wird, ändert sich auch der Wert von yourInt automatisch. Wenn der Wert von yourInt geändert wird, ändert sich auch der Wert von myInt automatisch.

Referenzen sind vom gleichen Typ.

Verweis auf eine Funktion

Genauso wie Sie eine Referenz auf einen Skalar haben können, können Sie auch eine Referenz auf eine Funktion haben. Das Codieren eines Verweises auf eine Funktion unterscheidet sich jedoch vom Codieren eines Verweises auf einen Skalar. Das folgende Programm veranschaulicht dies:

#einschließen
Verwenden von Namespace-Std;
float fn (float fl, int in)

Rückkehr fl;

int main()

float (&func)(float, int) = fn;
Schwimmerwert = func(2.5, 6);
cout << val << '\n';
0 zurückgeben;

Die Ausgabe ist 2.5.

Beachten Sie die erste Anweisung in der main-Funktion, die func zu einem Synonym von fn macht. Beide verweisen auf dieselbe Funktion. Beachten Sie die Einmalverwendung und Position von &. & ist hier also der Referenzoperator und nicht der Adressoperator. Um die Funktion aufzurufen, verwenden Sie einfach einen der Namen.

Ein Referenzbezeichner ist nicht gleich einem Zeigerbezeichner.

Funktion, die einen Pointer zurückgibt

Im folgenden Programm gibt die Funktion einen Zeiger zurück, der die Adresse des Objekts ist, auf das verwiesen wird:

#einschließen
Verwenden von Namespace-Std;
float *fn(float fl, int in)

schweben *fll = &fl;
Rückkehr voll;

int main()

Schwimmer *val = fn(2.5, 6);
cout << *val << '\n';
0 zurückgeben;

Die Ausgabe ist 2.5

Die erste Anweisung in der Funktion fn() dient nur dazu, ein Zeigerobjekt zu erstellen. Beachten Sie die Einmalverwendung und die Position von * in der Funktionssignatur. Beachten Sie auch, wie der Zeiger (Adresse) in der Funktion main() von einem anderen Zeigerobjekt empfangen wurde.

Funktion, die eine Referenz zurückgibt

Im folgenden Programm gibt die Funktion eine Referenz zurück:

#einschließen
Verwenden von Namespace-Std;
float &fn(float fl, int in)

Schwimmer &frr = fl;
Rückkehr frr;

int main()

float &val = fn(2.5, 6);
cout << val << '\n';
0 zurückgeben;

Die Ausgabe ist 2.5.

Die erste Anweisung in der Funktion fn() dient nur dazu, eine Referenz zu erstellen. Beachten Sie die Einmalverwendung und die Position von & in der Funktionssignatur. Beachten Sie auch, wie die Referenz in der main()-Funktion von einer anderen Referenz empfangen wurde.

Einen Zeiger an eine Funktion übergeben

Im folgenden Programm wird als Argument an die Funktion ein Zeiger gesendet, der eigentlich die Adresse eines Objekts mit Gleitkomma-Punkt ist:

#einschließen
Verwenden von Namespace-Std;
float fn(float *fl, int in)

zurück *fl;

int main()

Schwimmer v = 2.5;
Gleitkommawert = fn(&v, 6);
cout << val << '\n';
0 zurückgeben;

Die Ausgabe ist 2.5

Beachten Sie die Verwendung und Position von * für den float-Parameter in der Funktionssignatur. Sobald die Auswertung der Funktion fn() beginnt, erfolgt die folgende Anweisung:

float *fl = &v;

Sowohl fl als auch &v zeigen auf dasselbe spitze Objekt, das 2 . hält.5. *fl bei der return-Anweisung ist keine Deklaration; das bedeutet, der Wert des Pointer-Objekts, auf das das Pointer-Objekt zeigt.

Übergeben einer Referenz an eine Funktion

Im folgenden Programm wird eine Referenz als Argument an die Funktion gesendet:

#einschließen
Verwenden von Namespace-Std;
float fn(float &fl, int in)

Rückkehr fl;

int main()

Schwimmer v = 2.5;
Gleitkommawert = fn(v, 6);
cout << val << '\n';
0 zurückgeben;

Die Ausgabe ist 2.5

Beachten Sie die Verwendung und Position von & für den float-Parameter in der Funktionssignatur. Sobald die Auswertung der Funktion fn() beginnt, erfolgt die folgende Anweisung:

Schwimmer &fl = v;

Übergabe eines Arrays an eine Funktion

Das folgende Programm zeigt, wie Sie ein Array an eine Funktion übergeben:

#einschließen
Verwenden von Namespace-Std;
int fn(int arra[])

Rücksprung[2];

int main()

int arr[] = 000, 100, 200, 300, 400;
int val = fn(arr);
cout << val << '\n';
0 zurückgeben;

Der Ausgang ist 200.

In diesem Programm wird das Array übergeben. Beachten Sie, dass der Parameter der Funktionssignatur eine leere Array-Deklaration hat. Das Argument im Funktionsaufruf ist nur der Name eines erstellten Arrays.

Kann eine C++-Funktion ein Array zurückgeben??

Eine Funktion in C++ kann den Wert eines Arrays zurückgeben, aber nicht das Array. Das Kompilieren des folgenden Programms führt zu einer Fehlermeldung:

#einschließen
Verwenden von Namespace-Std;
int fn(int arra[])

Rückkehr arra;

int main()

int arr[] = 000, 100, 200, 300, 400;
int val = fn(arr);
0 zurückgeben;

Zeiger eines Zeigers

Ein Zeiger kann auf einen anderen Zeiger zeigen. Das heißt, ein Zeigerobjekt kann die Adresse eines anderen Zeigerobjekts haben. Sie müssen immer noch alle vom gleichen Typ sein. Das folgende Codesegment veranschaulicht dies:

int ptdInt = 5;
int *ptrInt = &ptdInt;
int **ptrptrInt = &ptrInt;
cout << **ptrptrInt << '\n';

Die Ausgabe ist 5.

Bei der Deklaration von Pointer-to-Pointer wird double * verwendet. Um den Wert des letzten spitzen Objekts zurückzugeben, wird weiterhin doppelt * verwendet.

Array von Zeigern

Das folgende Programm zeigt, wie ein Array von Zeigern codiert wird:

#einschließen
Verwenden von Namespace-Std;
int main()

int num0=000, num1=100, num2=200, num3=300, num4=400;
int *no0=&num0, *no1=&num1, *no2=&num2, *no3=&num3, *no4=&num4;
int *arr[] = no0, no1, no2, no3, no4;
cout << *arr[4] << '\n';
0 zurückgeben;

Die Ausgabe ist:

400

Beachten Sie die Verwendung und Position von * in der Deklaration des Arrays. Beachten Sie die Verwendung von *, wenn ein Wert im Array zurückgegeben wird. Bei Zeigern von Zeigern sind zwei * beteiligt. Bei Arrays von Zeigern ist ein * bereits berücksichtigt, da der Array-Bezeichner ein Zeiger ist.

Array von Strings variabler Länge

Ein String-Literal ist eine Konstante, die einen Zeiger zurückgibt. Ein Array von Strings variabler Länge ist ein Array von Zeigern. Jeder Wert im Array ist ein Zeiger. Pointer sind Adressen auf Speicherplätze und haben die gleiche Größe. Die Strings unterschiedlicher Länge befinden sich an anderer Stelle im Speicher, nicht im Array. Das folgende Programm veranschaulicht die Verwendung:

#einschließen
Verwenden von Namespace-Std;
int main()

const char *arr[] = "Frau", "Junge", "Mädchen", "Erwachsener";
cout << arr[2] << '\n';
0 zurückgeben;

Die Ausgabe ist "Mädchen".

Die Deklaration des Arrays beginnt mit dem reservierten Wort „const“ für konstant; gefolgt von „char“ für das Zeichen, dann dem Sternchen, *, um anzuzeigen, dass jedes Element ein Zeiger ist. Um einen String aus dem Array zurückzugeben, wird * aufgrund der impliziten Natur des Zeigers jedes Strings nicht verwendet used. Wenn * verwendet wird, wird das erste Element des Strings zurückgegeben.

Zeiger auf eine Funktion, die einen Zeiger zurückgibt

Das folgende Programm veranschaulicht, wie ein Zeiger auf eine Funktion, die einen Zeiger zurückgibt, codiert wird:

#einschließen
Verwenden von Namespace-Std;
int *fn()

int-Zahl = 4;
int *inter = #
zurück zwischen;

int main()

int *(*funktion)() = &fn;
int val = *func();
cout << val << '\n';
0 zurückgeben;

Die Ausgabe ist 4.

Die Deklaration eines Zeigers auf eine Funktion, die einen Zeiger zurückgibt, ähnelt der Deklaration eines Zeigers auf eine normale Funktion, jedoch mit einem vorangestellten Stern. Die erste Anweisung in der Funktion main() veranschaulicht dies. Um die Funktion mit dem Zeiger aufzurufen, setzen Sie * voraus.

Fazit

Um einen Zeiger auf einen Skalar zu erstellen, gehen Sie wie folgt vor:,

Schwimmer spitz;
Float *Zeiger = &pointed;

* hat zwei Bedeutungen: In einer Deklaration bezeichnet es einen Zeiger; um etwas zurückzugeben, ist es für den Wert des angezeigten Objekts.

Der Array-Name ist ein konstanter Zeiger auf das erste Element des Arrays.

Um einen Zeiger auf eine Funktion zu erstellen, können Sie Folgendes tun:,

int (*funktion)() = &fn;

wobei fn() eine an anderer Stelle definierte Funktion und func der Zeiger ist.

& hat zwei Bedeutungen: In einer Deklaration gibt es einen Verweis (Synonym) auf dasselbe Objekt wie ein anderer Bezeichner an; Wenn Sie etwas zurückgeben, bedeutet dies die Adresse von.

Um eine Referenz auf eine Funktion zu erstellen, können Sie Folgendes tun:,

float (&refFunc)(float, int) = fn;

wobei fn() eine an anderer Stelle definierte Funktion und refFunc die Referenz ist.

Wenn eine Funktion einen Zeiger zurückgibt, muss der zurückgegebene Wert von einem Zeiger empfangen werden. Wenn eine Funktion eine Referenz zurückgibt, muss der zurückgegebene Wert von einer Referenz empfangen werden.

Wenn Sie einen Zeiger an eine Funktion übergeben, ist der Parameter eine Deklaration, während das Argument die Adresse eines Objekts ist, auf das verwiesen wird. Bei der Übergabe einer Referenz an eine Funktion ist der Parameter eine Deklaration, während das Argument die Referenz ist.

Beim Übergeben eines Arrays an eine Funktion ist der Parameter eine Deklaration, während das Argument der Arrayname ohne [] ist. Die C++-Funktion gibt kein Array zurück.

Ein Pointer-to-Pointer benötigt ggf. zwei * statt eines.

Chrys

So ändern Sie Mauszeiger- und Cursorgröße, Farbe und Schema unter Windows 10
Der Mauszeiger und der Cursor in Windows 10 sind sehr wichtige Aspekte des Betriebssystems. Dies kann auch für andere Betriebssysteme gesagt werden, a...
Kostenlose und Open-Source-Spiele-Engines für die Entwicklung von Linux-Spielen
Dieser Artikel behandelt eine Liste von kostenlosen und Open-Source-Spiele-Engines, die für die Entwicklung von 2D- und 3D-Spielen unter Linux verwend...
Shadow of the Tomb Raider für Linux Tutorial
Shadow of the Tomb Raider ist die zwölfte Erweiterung der Tomb Raider-Reihe – ein Action-Adventure-Franchise von Eidos Montrealdos. Das Spiel wurde vo...