Adresse einer Variablen mit Zeiger

Lesezeit: 7 Minuten

Betrachten Sie den folgenden Code in C

int x=100;
int*addr=&x;

Ich weiß, dass addr die Adresse von x speichert. Eine Frage, die mir immer wieder in den Sinn kommt, ist, dass der addr-Zeiger seine eigene Adresse haben wird und auf die wieder mit dem kaufmännischen Und-Operator zugegriffen werden kann, und auch das wird irgendwo gespeichert, also haben wir hier eine unendliche Rekursion auf Adressen, also wo endet das?

  • Es endet nicht… du könntest eine haben int**************************. Auch, es sei denn, Sie schaffen ein Zeiger, die Adresse wird nirgendwo gespeichert.

    – StoryTeller – Unslander Monica

    13. Februar 2014 um 10:53 Uhr


  • Sie können die Adresse eines Hauses auf ein Blatt Papier schreiben und es in ein anderes Haus stecken. Dann können Sie die Adresse dieses Hauses auf ein anderes Blatt Papier schreiben und es in ein weiteres Haus kleben. Sie können dann die Adresse des dritten Hauses auf ein drittes Blatt Papier schreiben und es in ein viertes Haus kleben. also haben wir hier eine unendliche Rekursion auf Adressen, also wo endet das?

    – Shahbaz

    13. Februar 2014 um 11:17 Uhr


  • Es endet, wenn Sie aufhören, hinzuzufügen * zu einem Typ. Denk darüber so. Alle Typen mögen int *, int **, usw. sind zur Kompilierzeit bekannt. Wenn es ein implementierungsdefiniertes Indirektionslimit gibt, werden Sie es zur Kompilierzeit wissen, also ist es nicht wirklich unendlich in dem Sinne, dass eine Schleife oder ein rekursiver Funktionsaufruf unendlich sein kann.

    – Brandin

    13. Februar 2014 um 11:27 Uhr

Benutzer-Avatar
entspannen

Die Adresse von addr wird nirgendwo explizit “gespeichert”, es ist einfach so. Wenn Sie eine zweite Variable deklarieren und zum Speichern dieser Adresse verwenden, müssen Sie sicher sein, dass sie Platz benötigt:

int **addr2 = &addr;

Sie können sich die Erinnerung als eine Reihe von Kästchen vorstellen. Angenommen 4 Byte int und Zeigern und Little-Endian-Byte-Reihenfolge könnte Ihr Szenario so aussehen:

+----------+--+--+--+--+
| Address  |Data bytes |
+----------+--+--+--+--+
|0x00000000|64|00|00|00|
+----------+--+--+--+--+
|0x00000004|00|00|00|00|
+----------+--+--+--+--+

Die Adresse wird links angezeigt, die dort enthaltenen Bytes rechts. Sie können den Wert sehen 100 in den ersten vier Bytes gespeichert (100 dezimal ist 0x64 in Hex). Die zweite 4-Byte-Position enthält den Wert 0x00000000, was die Adresse von ist x. Die Adresse 0x00000004 ist nirgendwo hinterlegt.

Wenn wir jetzt einen zweiten Zeiger hinzufügen, würden wir mehr Speicher verbrauchen:

+----------+--+--+--+--+
|0x00000008|04|00|00|00|
+----------+--+--+--+--+

Das wäre der Speicher, der verwendet wird, um das darzustellen addr2 Zeiger, und Sie können sehen, dass er die Adresse von enthält addralso 0x00000004.

Dereferenzierung addr2 mit dem Ausdruck *addr2 würde den Wert an Adresse 0x00000004 ergeben, also 0x00000000 mit dem Typ int *. Das erneute Dereferenzieren ergibt die int an dieser Adresse, dh 0x00000064.

Da dieses Speicherlayout vom Compiler gewählt wird, “kennt” er die beteiligten Adressen und kann diese einfach ersetzen, wenn Codereferenzen verwendet werden addr2, generiert es Anweisungen, die die Adresse 0x00000008 manipulieren, und so weiter. In echtem Code würde dies wahrscheinlich alles auf dem Stack passieren, aber das Prinzip ist dasselbe.

Schlussbemerkung: Beachten Sie den Rat von @Phil Perry; das Obige vereinfacht und macht viele Dinge, die etwas abstrakt sein sollen, unverständlich. So funktioniert es wirklich auf vielen aktuellen Architekturen, aber viele der erwähnten Dinge werden von C nicht garantiert, sodass Sie sich nicht wirklich darauf verlassen können, dass sie immer wahr sind. Ich meinte das Obige als Illustration, um die Konzepte (hoffentlich) etwas weniger vage zu machen.

  • Danke besonders für deine Bilder. Es hat geholfen.

    – Nasener

    13. Februar 2014 um 11:08 Uhr

  • Sie haben ein Sternchen weggelassen: int** addr2=&addr.

    – marczellm

    13. Februar 2014 um 13:11 Uhr

  • @marczellm Danke, behoben!

    – abschalten

    13. Februar 2014 um 13:11 Uhr

  • Nur um ein hinzuzufügen Vorsicht: nicht denken Zeiger als eine Art ganze Zahl. Es gibt keine Garantie dafür, dass ein Zeiger in eine bestimmte Anzahl von Bytes passt oder dass es sich sogar um eine einzelne Zahl handelt (denken Sie an die alte segmentierte Intel 808x-Architektur). Seien Sie sehr vorsichtig, was Sie mit Zeigern zu tun versuchen!

    – Phil Perry

    13. Februar 2014 um 17:05 Uhr

  • @PhilPerry Guter Punkt, ich habe einige Worte dahingehend bearbeitet. Ich denke das sizeof (T) kann für jeden Zeigertyp ausgewertet werden Tnicht wahr?

    – abschalten

    14. Februar 2014 um 8:13 Uhr

Benutzer-Avatar
Sergej Kalinitschenko

Wenn Sie eine Adresse speichern, brauchen Sie natürlich einen Ort, an dem sie gespeichert werden kann (z Ein weiterer Adresse), so dass Sie dies so lange fortsetzen können, wie Sie möchten. Dies endet genau dann, wenn Sie es beenden möchten.

int         a = 1;
int       *pa = &a;
int     **ppa = &pa;
int   ***pppa = &ppa;
int ****ppppa = &pppa;
...

Hier ist eine kurze Analogie: Nehmen wir an, Sie haben ein Notizbuch mit nummerierten Seiten und Zeilen. Angenommen, Sie machen eine Notiz auf Seite 3, Zeile 8, und Sie möchten diese Notiz dann von einer anderen Stelle aus referenzieren. Vielleicht können Sie auf Seite 7, Zeile 20, einen Hinweis schreiben “siehe Hinweis auf Seite 3, Zeile 8”. Jetzt hat die Referenz eine eigene “Adresse” – nämlich Seite 7, Zeile 20. Sie können auch darauf verweisen – auf Seite 8, Zeile 1, könnten Sie schreiben “siehe Hinweis auf Seite 7, Zeile 20”. Sie können diese Verweiskette beliebig lange fortsetzen.

  • Bedenke auch, dass du das nicht kannst &&a. Warum ist das so? Da &a hat keine Adresse, bis Sie sie irgendwo speichern.

    – Claudius

    13. Februar 2014 um 20:41 Uhr

C implementiert das, was a genannt wird von Neumann-Maschine. Sie können C auf anderen Arten von Computern kompilieren, wenn Sie den Computer dazu bringen können, das zu tun, was eine von Neumann-Maschine tun würde.

Was ist also eine von Neumann-Maschine? Mit Entschuldigung an die BBC gehen die meisten Leute davon aus, dass Programme im Speicher strenge und unterschiedliche Vorstellungen von Code und Daten haben, aber tatsächlich – aus einer einheitlichen, von Neumann-Perspektive – ist der Speicherplatz eines Programms eher wie ein großer Ball aus wackeligen, wackeligen Zahlen -wurmhaft… Sachen. Sie können darauf wie auf Daten zugreifen und sie sogar ändern, oder Sie können sie wie Code ausführen. Letzteres ist jedoch keine gute Idee, wenn Sie nicht sicher sind, ob es sich um funktionierenden Code handelt, was einer der Gründe dafür ist, dass die Leute Assembler nicht mehr sehr oft verwenden. Höhere Programmiersprachen organisieren die Zahlen sorgfältig in etwas, das (idealerweise) funktioniert: Sie sind darin nicht perfekt, und C ist darin weniger perfekt als die meisten anderen. Aber sie erledigen normalerweise die Arbeit.

Was hat das jetzt mit deiner Frage zu tun? Wie Sie sagen, muss jede Variable eine Adresse haben, und C muss diese Adressen kennen, um sie verwenden zu können. Die genauen Implementierungsdetails können von Compiler zu Compiler und manchmal von verschiedenen Einstellungen innerhalb des Compilers variieren, aber in einigen Fällen kennt das Programm nicht einmal mehr die Variablennamen, wenn es die Ebene des Maschinencodes erreicht. Die Adressen sind alles, was übrig bleibt, und sie werden tatsächlich verwendet.

Diese Adressen werden vom Compiler festgelegt. Letztendlich werden sie Teil des Codes selbst. Sie werden in Bereichen aufbewahrt, auf die Sie normalerweise keinen Zugriff haben sollten, aber können, wenn Sie WIRKLICH müssen. Diese Bereiche sind im Grunde dort, wo die Rekursion aufhört.

Sie haben keine unendliche Rekursion. Jede Variable hat ihre Adresse und das war’s. Wenn Sie nun eine Variable definieren, die gleich der Adresse einer anderen Variablen ist, dann wird die Adressvariable selbst irgendwo gespeichert und hat eine Adresse. Eine Adresse selbst hat keine Adresse Die Variable das speichert es tut.

Benutzer-Avatar
Bathseba

Konzeptionell wird dem Zeiger nur Speicherplatz zugewiesen, wenn Sie die Adresse speichern:

1) In Ihrem Fall: int*addr=&x;, addr wird besetzen sizeof(int*) Byte Speicher. (Aber ein Compiler behält sich das Recht vor, den Zeiger nicht im Speicher zu speichern: Er könnte ihn in einem CPU-Register behalten).

2) &x weist keinen Speicher explizit zu.

3) &&x, &&&x usw. sind syntaktisch nicht gültig, sodass Sie sich hier keine Gedanken über eine mögliche Rekursion machen müssen.

Die Tatsache, dass && Früher war dies eine illegale Syntax, die die Verwendung von C++ 11 erlaubte R-Wert-Referenzen.

Benutzer-Avatar
Ferenc Deak

Natürlich hat der Adresszeiger seine eigene Adresse, aber wenn Sie nicht speziell auf die darin enthaltene Adresse zugreifen, wird sie nicht verwendet, daher gibt es dafür keine Rekursion …

Benutzer-Avatar
irshad.ahmad

Lass es uns so aussehen. Wir haben limited Erinnerung. Außerhalb dieses gesamten Speichers wird den Compilern eine begrenzte Menge an Speicher zugewiesen STORE ihre Variablen. Sie können so viele Variablen deklarieren, wie Sie möchten, ABER es wird eine Zeit kommen, in der Sie nicht mehr Variablen erstellen können, WEIL die allocated memory wird der Platz knapp. Also zu deiner Frage, die Antwort lautet NO. Aufgrund des begrenzt zugewiesenen Speicherplatzes zum Speichern von Variablen gibt es keine unendliche Rekursion.

1353460cookie-checkAdresse einer Variablen mit Zeiger

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy