Große Frage.
Dein erster Block ist korrekt. Ein Zeiger ist eine Variable, die die Adresse einiger Daten enthält. Der Typ dieses Zeigers teilt dem Code mit, wie er den Inhalt der Adresse interpretiert, die von diesem Zeiger gehalten wird.
Das Konstrukt:
%Vor%Wird als Deferenzierung eines Zeigers bezeichnet. Das heißt, Sie können auf die Adresse zugreifen, auf die der Zeiger zeigt, und darauf lesen und schreiben wie eine normale Variable. Hinweis:
%Vor%Das obige ist nur ein mnemotechnisches Gerät, das ich benutze.
Es ist selten, dass Sie einem Zeiger jemals einen numerischen Wert zuweisen ... vielleicht, wenn Sie für eine bestimmte Umgebung entwickeln, die einige 'bekannte' Speicheradressen hat, aber auf Ihrer Ebene, würde ich keine Sorge haben zu viel darüber.
Verwenden Sie
%Vor%würde letztendlich zu einem Fehler führen. Sie würden versuchen, etwas zu stören, das kein Zeiger ist, so dass Sie wahrscheinlich einen Systemfehler bekommen, weil wer weiß, wohin es zeigt.
&test1
und &test2
sind tatsächlich Zeiger auf test1
und test2
.
Zeiger auf Zeiger sind sehr nützlich und eine Suche nach Zeiger auf einen Zeiger führt Sie zu einigen Ressourcen Das ist viel besser als ich.
Es sieht so aus, als hätten Sie den ersten Teil richtig.
Ein zufälliger Gedanke: Es gibt verschiedene Konventionen darüber, wo dieses *
-Zeichen stehen soll. Ich bevorzuge meine mit dem Variablennamen, wie in int *test1
, während andere int* test1
bevorzugen. Ich bin nicht sicher, wie üblich es ist, es in der Mitte schweben zu lassen.
Ein weiterer nebensächlicher Gedanke: test2 = 3.0
weist Floating-Point 3 einen Wert von test2
zu. Das gleiche Ende könnte mit test2=3
erreicht werden, in welchem Fall die 3 implizit von einer ganzen Zahl in eine Gleitkommazahl umgewandelt wird. Die Konvention, die Sie gewählt haben, ist wahrscheinlich in Bezug auf Klarheit sicherer, aber nicht unbedingt notwendig.
Keine Nebenkosten
*test1=3
weist der von test
angegebenen Adresse 3 zu.
test1=3
ist eine Zeile, die eine Bedeutung hat, die ich aber für sinnlos halte. Wir wissen nicht, was an Speicherplatz 3 ist, ob es sicher ist, es zu berühren, oder ob wir es berühren dürfen.
Deshalb ist es praktisch, etwas wie
zu verwenden %Vor% Der Befehl &var
gibt den Speicherort von var
zurück und speichert ihn in pointy
, damit wir später mit *pointy
darauf zugreifen können.
Aber ich könnte auch so etwas machen:
%Vor% Und hier sehen Sie vielleicht etwas wie test1=3
: Zeiger können genau wie Zahlen addiert und subtrahiert werden, so dass Sie Offsets wie diese speichern können.
&test1
ist ein Zeiger auf einen Zeiger, aber das klingt irgendwie verwirrend für mich. Es ist wirklich die Adresse im Speicher, in der der Wert von test1
gespeichert ist. Und test1
speichert zufällig nur die Adresse einer anderen Variablen als Wert. Sobald Sie auf diese Weise an Zeiger denken (Adresse im Speicher, Wert dort gespeichert), wird es einfacher mit ... zu arbeiten ... oder zumindest denke ich das.
Ich weiß nicht, ob *test2
"Bedeutung" an sich hat. Im Prinzip könnte es nützlich sein, wenn wir uns vorstellen, dass der *
-Befehl den Wert von test2
als einen Speicherplatz im Speicher annehmen und den dort gefundenen Wert zurückgeben wird. Aber da Sie test2
als Float definieren, ist es schwierig vorherzusagen, wo im Speicher wir landen würden, wenn test2=3
nicht auf den dritten Punkt von irgendwas gesetzt wird (schauen Sie in der IEEE754-Spezifikation nach, warum). Aber ich wäre überrascht, wenn ein Compiler so etwas erlauben würde.
Schauen wir uns ein anderes schnelles Beispiel an:
%Vor%Sie sehen also, dass Sie Zeiger so aneinander ketten können, so viele hintereinander wie Sie möchten. Dies könnte auftreten, wenn Sie ein Array von Zeigern hätten, das mit den Adressen vieler Strukturen gefüllt wäre, die Sie aus dem dynamischen Speicher erstellt haben, und diese Strukturen enthalten Zeiger auf dynamisch zugewiesene Dinge selbst. Wenn es Zeit wird, einen Zeiger auf einen Zeiger zu verwenden, werden Sie es wahrscheinlich wissen. Für jetzt mach dir keine Sorgen um sie.
Lassen Sie uns zunächst etwas Verwirrung stiften: Das Wort "Zeiger" kann sich entweder auf eine Variable (oder ein Objekt) mit einem Zeigertyp oder auf einen Ausdruck mit dem Zeigertyp beziehen. In den meisten Fällen, wenn Leute von "Zeigern" sprechen, meinen sie Zeigervariablen.
Ein Zeiger kann ( muss ) auf ein Ding (ein "Objekt" im Standardsprachgebrauch) zeigen. Es kann nur auf die richtige Art der Sache hinweisen; Ein Zeiger auf int soll nicht sein, um auf ein float-Objekt zu zeigen. Ein Zeiger kann auch NULL sein; In diesem Fall gibt es nichts, worauf man hinweisen könnte.
Ein Pointertyp ist auch ein Typ und ein Zeigerobjekt ist auch ein Objekt. So ist es möglich, einen Zeiger auf Zeiger zu konstruieren: Der Zeiger auf Zeiger speichert nur die Adressen des Zeigerobjekts.
Was ein Zeiger kann nicht sein:
p = &4;
ist unmöglich. 4 ist ein Literalwert, der nicht in einem Objekt gespeichert ist und daher keine Adresse hat. p = &(1+4);
ist unmöglich, weil der Ausdruck "1 + 4" keinen Ort hat. p = &sin(pi);
ist unmöglich; Der Rückgabewert ist kein Objekt und hat daher keine Adresse. Es gibt einige "Ausnahmen" zum obigen Skelett (Leere Zeiger, Casting, Zeige ein Element über ein Array-Objekt hinaus), aber zur Klarheit Diese sollten als Verfeinerungen / Änderungen gesehen werden, IMHO.