Was ist der Unterschied zwischen einer Variablen und einem Speicherort? [geschlossen]

38

In letzter Zeit habe ich versucht, Zeiger auf visuelle Weise als Karteikarten zu erklären.

Frage 001: Dies ist die Zeichnung eines Speicherorts im Computerspeicher. Stimmt es, dass seine Adresse ist 0x23452? Warum?

Bildbeschreibung hier eingeben

Antwort: Ja, da 0x23452beschrieben wird, wo der Computer diesen Ort finden kann.


Frage 002: Stimmt es, dass das Zeichen bim Speicherort gespeichert ist 0x23452? Warum?

Bildbeschreibung hier eingeben

Antwort: Nein, da der Charakter atatsächlich darin gespeichert ist.


Frage 003: Stimmt es, dass ein Zeiger im Speicherort gespeichert ist 0x23452? Warum?

Bildbeschreibung hier eingeben

Antwort: Ja, da die Adresse des Speicherorts 0x34501darin gespeichert ist.


Frage 004: Stimmt es, dass ein Zeiger im Speicherort gespeichert ist 0x23452? Warum?

Bildbeschreibung hier eingeben

Antwort: Ja, da die Adresse eines anderen Speicherorts darin gespeichert ist.


Nun zu dem Teil, der mich beunruhigt hat. Ein Softwareentwickler erklärte mir die folgenden Hinweise:

Ein Zeiger ist eine Variable, deren Wert die Speicheradresse einer anderen Variablen ist.

Anhand der vier Karteikarten, die ich Ihnen allen gezeigt habe, würde ich Zeiger auf etwas andere Weise definieren:

Ein Zeiger ist ein Speicherort, dessen Wert die Speicheradresse eines anderen Speicherorts ist.

Ist es sicher zu sagen, dass eine Variable dasselbe ist wie ein Speicherort?

Wenn nicht, wer hat dann Recht? Was ist der Unterschied zwischen einer Variablen und einem Speicherort?

progner
quelle
37
Es gibt eine implizite Annahme hier , dass jeder diese Bilder zu lesen Ihre Absicht wissen , dass die hexadezimale Zahl unter dem Feld ist eine Speicheradresse, und dass das a, 0x23453. nilusw. Zeug in ihnen sind die Werte. Das mag Ihnen offensichtlich erscheinen, aber ich würde nicht gerne entscheidende Antworten auf diese Fragen geben, ohne zu sehen, wie diese Felder definiert sind. Es gibt wirklich keine Möglichkeit herauszufinden, ob es sich abei dem zweiten Bild um ein Zeichen, eine Zeichenfolge (falls sie sich unterscheiden) oder den Namen einer Variablen handelt. Wenn es eine Zeichenfolge ist, ist niles dann auch eine Zeichenfolge? Oder ein "Null" -Wert?
Ilkkachu
39
Frage 1 ist eine schlechte Frage. Dies müssen Sie den Lesern mitteilen, bevor sie die anderen Fragen beantworten können. Anstelle einer Frage sollte dem Leser eine Information gegeben werden: "In den folgenden Fragen sind die Kästchen Speicherplätze und die Hexadezimalzahlen darunter sind ihre Adressen".
17 vom 26.
15
Frage 3 ist im gegebenen Kontext nicht zu beantworten. Auf Byte-Ebene kann nicht festgestellt werden, wie der im Speicher gespeicherte Wert auf Anwendungsebene interpretiert / verwendet wird.
17 vom 26.
6
Bemerkenswert: Alles, was Sie hier schreiben, ist für C oder C ++ wahr, aber falsch für im Grunde jede Sprache, die keine explizite Zeigerreferenzierung / Dereferenzierung hat. Die gesamte Metapher von Variablen, bei der es sich um Slots handelt, in die Werte geschrieben werden, zerfällt für eine Sprache (wie Python, Java, C #, Ruby, JavaScript oder viele andere), bei der durch die Zuweisung lediglich eine Variable auf ein Objekt verweist, ohne es zu kopieren , und Mutationen am Objekt sind durch alle Variablen sichtbar, die darauf verweisen. Pythons Dokumentation verwendet aus diesem Grund die alternative Metapher von Variablen als Namensschilder, die an Objekten hängen.
Mark Amery
19
Übrigens, und verzeihen Sie mir, wenn Sie dies bereits verstehen, aber es sieht so aus, als ob dies ein Punkt der Verwirrung sein könnte - diese "0x23452" -Notation ist nur eine Möglichkeit, eine Zahl im hexadezimalen Format zu bezeichnen, und dient nur der Vereinfachung. Aber es ist nur eine Zahl - das 0x-Präfix bedeutet in keiner Weise, dass es sich um einen Zeiger handelt. Was im Speicher gespeichert ist, ist buchstäblich nur eine bedeutungslose Zahl (Sie könnten Speicherorte mit einfachen Dezimalzahlen kennzeichnen). Die Bedeutung (dh wie die Zahl interpretiert werden soll) ergibt sich aus der Sprache - dem Typ der Variablen und der Art und Weise, wie sie verwendet wird.
Filip Milovanović

Antworten:

69

Eine Variable ist ein logisches Konstrukt, das zur Intention eines Algorithmus gehört, während ein Speicherort ein physikalisches Konstrukt ist, das den Betrieb eines Computers beschreibt. Im Allgemeinen wird zur Ausführung eines Programms eine (vom Compiler generierte) Zuordnung zwischen dem logischen Begriff einer Variablen und dem Speicher des Computers vorgenommen.

(Auch in der Assemblersprache haben wir eine Vorstellung von (logischen) Variablen, die Algorithmen und Absichten sowie (physischen) Speicherorten entsprechen, obwohl sie in der Assemblersprache stärker zusammengeführt sind.)

Eine Variable ist ein übergeordnetes Konzept. Eine Variable steht entweder für eine unbekannte (wie in Mathematik oder Programmieraufgabe) oder einen Platzhalter, der durch einen Wert ersetzt werden kann (wie in Programmierung: Parameter).

Ein Speicherort ist ein Konzept auf niedriger (er) Ebene. Ein Speicherort kann verwendet werden, um einen Wert zu speichern, manchmal um den Wert einer Variablen zu speichern. Ein CPU-Register ist jedoch eine andere Möglichkeit, den Wert einiger Variablen zu speichern. CPU-Register sind ebenfalls Speicherorte auf niedriger (er) Ebene, aber sie sind keine Speicherorte, da sie keine Adressen, sondern nur Namen haben.

In gewissem Sinne ist eine Variable ein Abstraktionsmechanismus, um die Absicht des Programms auszudrücken, wohingegen ein Speicherort eine physikalische Entität der Verarbeitungsumgebung ist, die das Speichern und Abrufen ermöglicht.

Frage 003: Stimmt es, dass ein Zeiger im Speicherort 0x23452 gespeichert ist? Warum?

Wir können nicht sicher sagen. Nur weil es dort einen Wert gibt, der als Adresse funktionieren würde, heißt das nicht, dass es sich um diese Adresse handelt, sondern stattdessen die ganze Zahl (Dezimalzahl) 144466. Wir können keine Annahmen über die Interpretation von Werten treffen, die nur darauf beruhen, wie sie numerisch erscheinen.

Frage 004: Stimmt es, dass ein Zeiger im Speicherort 0x23452 gespeichert ist? Warum?

Dies ist in der Tat eine seltsame Frage. Sie erwarten einige Annahmen, die auf den Feldern basieren. Beachten Sie jedoch, dass die Adressen für jedes Feld um 1 erhöht werden. In jedem modernen Computer würde dies bedeuten, dass jede Box eine Byte - Byte - Adressierbarkeit enthalten kann. Dies ist seit Jahrzehnten die Norm. Ein Byte besteht jedoch nur aus 8 Bits und kann zwischen 0 und 255 liegen (für Werte ohne Vorzeichen). Sie weisen jedoch einen viel größeren Wert auf, der in einer dieser Adressen gespeichert ist, und sind daher sehr verdächtig. (Dies könnte funktionieren, wenn dies eine wortadressierte Maschine wäre, aber das sagt es nicht, und heutzutage sind es nur wenige Maschinen, obwohl dies bei einigen Lehrmaschinen der Fall ist.)

Anhand der vier Karteikarten, die ich Ihnen allen gezeigt habe, würde ich Zeiger auf etwas andere Weise definieren:

Ein Zeiger ist ein Speicherort, dessen Wert die Speicheradresse eines anderen Speicherorts ist.

Während es Situationen gibt, in denen dieses Denken richtig ist, mischen Sie hier Metaphern. Der Begriff einer Variablen geht auf den Algorithmus und seine Absicht zurück - es muss nicht angenommen werden, dass alle Variablen Speicherplätze haben. Einige Variablen (insbesondere Arrays) haben Speicherplätze, da Speicherplätze die Adressierung unterstützen (während CPU-Register nur benannt und nicht indiziert werden können).

Zur Ausführung gibt es eine logische Zuordnung zwischen Variablen & Anweisungen und Prozessorspeicherplätzen & Prozessorbefehlssequenzen. Eine Variable, deren Wert sich nie ändert (z. B. eine Konstante), benötigt nicht unbedingt einen Speicherplatz, da der Wert nach Belieben reproduziert werden kann (z. B. nach Bedarf für vom Compiler generierte Codesequenzen).

Erik Eidt
quelle
4
Und selbst 8-Bit-Bytes sind immer noch nicht universell.
Deduplizierer
14
@JimmyJames Betrachten Sie den Fall eines forSchleifenindex, wenn der Compiler entscheidet, die Schleife vollständig zu entrollen. Nirgendwo in dem erzeugten Ausgabecode (sei es Baugruppen- oder Maschinencode oder Bytecode) befindet sich ein Speicherort, an dem der Schleifenzähler gespeichert wird. Aber es ist immer noch eine Variable.
Dmckee
4
@JimmyJames, im Fall des Zeigers für die entrollte Schleife, dann ja, wenn Ihr Code tatsächlich den Wert des Zählers verwendet, muss er irgendwo geladen werden , aber (a) dieser Ort könnte ein Register sein, und (b) Es gibt im Prinzip keinen Grund, warum es bei jeder Iteration der entrollten Schleife derselbe Ort sein müsste .
Solomon Slow
3
Wenn die Schleife so etwas wie das Kopieren eines Arrays fester Länge in ein Array sourcegleicher Länge tut, könnte desteine Schleife, die so codiert ist for (int i=0; i<8; ++i) dest[i] = source[i];, bis zu einem dest++ = source++;Punkt kompiliert werden, der der Wiederholung der entsprechenden Häufigkeit entspricht. Mit dem Schleifenzähler selbst ist nirgends etwas zu sehen (auch nicht im Register), und nur die Anzahl der Wiederholungen gibt Auskunft über den Schleifenzustand.
dmckee
2
Die Unterscheidung wird durch Sprachen wie C etwas verwirrt, deren Semantik eng auf einer Abstraktion einer Maschine basiert, deren Gedächtnis aus nummerierten Stellen besteht.
Michael Kay
20

Ist es sicher zu sagen, dass eine Variable dasselbe ist wie ein Speicherort?

Nein. Variable und Speicherort sind zwei Abstraktionen auf zwei verschiedenen Abstraktionsebenen. Variable und Zeiger sind auf Code- / Sprachebene ein übergeordnetes Konzept, der Speicherort ist auf Maschinenebene ein untergeordnetes Konzept. Sobald ein Code in eine ausführbare Datei kompiliert wurde, gibt es keine Variablen mehr. Der Versuch, auf diese Weise über Speicherort und Variablen zu sprechen, ist ein kategorischer Fehler.

Eine Variable kann unter Verwendung des Speichers implementiert werden, aber nicht immer, da ein Compiler eine Berechnung optimieren und alle Berechnungen, die sich auf eine Variable beziehen, vollständig in Registern ausführen kann, oder eine einzelne Variable mehreren Speicherstellen zuordnen kann oder einen einzelnen Speicher verwenden kann Speicherort für mehrere Variablen.

Ein Zeiger ist ein Speicherort, dessen Wert die Speicheradresse eines anderen Speicherorts ist.

Diese Reihe von Karteikarten ist so verwirrt, dass sie nicht nur nicht richtig, sondern auch nicht falsch sind.

Lüge Ryan
quelle
1
Once a code had been compiled into an executable, there's no longer any variables.Damit bin ich wohl nicht einverstanden. Es ist richtig, dass Ihre Variable, wie Sie sie kennen (dh mit diesem Namen), nicht mehr existiert, aber Ihre Formulierung scheint darauf hinzudeuten, dass die kompilierte ausführbare Datei nur Speicheradressen verwendet. Das stimmt nicht. Ihre kompilierte, aber nicht ausführbare ausführbare Datei hat keine Ahnung, welche Speicheradressen sie bei der Ausführung verwendet. Das Konzept einer Variablen (dh eine wiederverwendbare Referenz auf die Speicheradresse, die zur Laufzeit zugewiesen wird) ist in der kompilierten ausführbaren Datei noch vorhanden.
Flater
2
Oder der Compiler kann die Variable auf verschiedene Weise komplett wegoptimieren. Etwas vorberechnen, unnötige Variablen entfernen. Wenn die Variable eine Konstante ist, könnte der Compiler am Ende CPU-Anweisungen verwenden, die Konstanten verwenden, und ich würde argumentieren, dass dies nicht mehr als Variable gilt, die irgendwo ist.
Kutschkem
16

Variablen sind Sprachkonstrukte . Sie haben einen Namen, befinden sich in einem Bereich, können von anderen Teilen des Codes referenziert werden usw. Sie sind eine logische Einheit. Dem Compiler steht es frei, dieses Sprachkonstrukt nach Belieben zu implementieren, sofern das beobachtbare Verhalten dem durch den Sprachstandard vorgegebenen entspricht. Daher muss die Variable nicht einmal irgendwo gespeichert werden, wenn der Compiler nachweisen kann, dass dies nicht erforderlich ist.

Speicherplätze sind ein Hardwarekonzept . Sie kennzeichnen einen Platz im virtuellen / physischen Speicher. Jeder Speicherort hat genau eine physikalische Adresse und eine beliebige Anzahl von virtuellen Adressen, die zur Manipulation verwendet werden können. An jedem Speicherplatz ist aber immer genau ein Byte gespeichert.

Zeiger sind eine besondere Art von Werten . Etwas zu sagen, ist ein Zeiger, ist vergleichbar damit, etwas von Typ zu sagen double. Es gibt an, wie viele Bits für den Wert verwendet werden und wie diese Bits interpretiert werden. Es bedeutet jedoch nicht, dass dieser Wert in einer Variablen gespeichert ist, und es bedeutet auch nicht, dass dieser Wert im Speicher gespeichert ist.


Um ein Beispiel in C zu geben: Wenn ich ein 2D-Array habe int foo[6][7];und damit auf ein Element davon zugreife foo[1][2], fooist dies eine Variable, die ein Array enthält. Wenn fooes in diesem Kontext verwendet wird, wird es in einen Zeiger auf das erste Element des Arrays umgewandelt. Dieser Zeiger wird weder in einer Variablen noch im Speicher gespeichert. Sein Wert wird nur in einem Register der CPU generiert, verwendet und dann vergessen. Ebenso wird der Ausdruck foo[1]in diesem Zusammenhang in einen anderen Zeiger umgewandelt, der wiederum nicht in einer Variablen enthalten ist, nicht im Speicher gespeichert, sondern in der CPU berechnet, verwendet und vergessen wird. Die drei Konzepte Variable , Speicherort und Zeiger sind wirklich drei verschiedene Konzepte.


Übrigens, ich meinte wirklich "an jedem Speicherort ist immer genau ein Byte gespeichert". Dies war in der Steinzeit vor etwa fünfzig Jahren nicht der Fall, aber es gilt für praktisch alle Hardware, die heute verwendet wird. Immer wenn Sie einen Wert im Speicher ablegen, der größer als ein Byte ist, verwenden Sie mehrere aufeinanderfolgende Speicherorte. Dh (unter der Annahme einer Big-Endian-Bytereihenfolge) die Nummer 0x01234567 wird im Speicher als gespeichert

+------+------+------+------+
| 0x01 | 0x23 | 0x45 | 0x67 |
+------+------+------+------+
    ^      ^      ^      ^
    |      |      |      |
 0x4242 0x4243 0x4244 0x4245

(Little-Endian-Maschinen wie die X86-Architektur speichern die Bytes in umgekehrter Reihenfolge.) Dies gilt auch für Zeiger: Ein Zeiger auf einer 64-Bit-Maschine wird in acht aufeinanderfolgenden Bytes mit jeweils eigener Speicheradresse gespeichert. Sie können nicht auf eine Speicherzelle schauen und sagen: "Oh, das ist ein Zeiger!" Sie sehen immer nur Bytes, wenn Sie den Speicher betrachten .

cmaster
quelle
Woher weiß der Computer, wann eine Gruppe aufeinanderfolgender Speicherorte beginnt und endet?
Progner
6
@progner Das tut es nicht. Es interpretiert die Bytes im Speicher gemäß den Anweisungen, die es erhält. Diese Anweisungen werden auch nur in einer Folge von Bytes selbst gespeichert. Für die CPU besteht der einzige Unterschied zwischen einem Byte, das einen Befehl enthält, einem Byte, das ein Zeichen enthält, und einem Byte, das einige Gleitkommabits enthält, darin, wie es angewiesen wurde, dieses Byte zu verwenden. Wenn das Byte abgerufen wird, weil der Programmzähler darauf zeigt, wird es als Anweisung verwendet. Wenn es abgerufen wird, weil eine Anweisung sagt, dass es in ein Gleitkomma-Register geladen werden soll, wird es als Gleitkomma-Daten verwendet.
29.
7
@progner Das war eigentlich die Schlüsselinnovation der von-Neuman-Architektur: Befehle und Daten im selben Speicher zu speichern, damit Befehle Daten ändern können, die später als weitere Befehle ausgeführt werden. Dies ermöglichte eine Selbstmodifizierung des Codes, aber es ermöglichte auch dem Kernel eines Systems, ein Programm in den Speicher zu laden und dann die CPU anzuweisen, dieses Programm auszuführen. Vor von-Neuman erhielten Computer wie die Zuse-Maschinen ihre Anweisungen über einen Kanal, der völlig unabhängig von den Daten war, mit denen sie arbeiteten.
29.
5

Lassen Sie mich auf Ihre eigentliche Frage konzentrieren - "Wer hat Recht?" beim Vergleich dieser beiden Aussagen:

  • Ein Zeiger ist eine Variable, deren Wert die Speicheradresse einer anderen Variablen ist
  • Ein Zeiger ist ein Speicherort, dessen Wert die Speicheradresse eines anderen Speicherorts ist.

Die Antwort darauf ist keine . Der erste spricht von einer "Speicheradresse einer anderen Variablen", aber Variablen müssen nicht unbedingt Speicheradressen haben, wie die anderen Antworten bereits erklärt haben. Der zweite besagt "ein Zeiger ist ein Speicherort", aber ein Zeiger ist buchstäblich nur eine Zahl, die in einer Variablen gespeichert werden kann, aber wie zuvor hat eine Variable nicht notwendigerweise eine Speicheradresse.

Einige Beispiele für genauere Aussagen:

  • "Ein Zeiger ist eine Zahl, die die Speicheradresse eines Speicherorts darstellt", oder

  • "Eine Zeigervariable ist eine Variable, deren Wert die Speicheradresse eines Speicherorts ist."

  • "Eine Speicheradresse kann einen Zeiger enthalten, der die Speicheradresse eines Speicherorts darstellt."

Beachten Sie, dass manchmal der Begriff "Zeiger" als Abkürzung für "Zeigervariable" verwendet wird, was in Ordnung ist, solange dies nicht zu Verwirrung führt.

Doc Brown
quelle
Sie können "ein anderes" in "ein" ändern, da ein Zeiger auf sich selbst zeigen kann.
Pieter B
@PieterB: nitty, nitty ;-) bin mir nicht sicher, ob das wirklich klarer wird, da ich nur den ursprünglichen Wortlaut in dem Maße ändern wollte, wie es wirklich erforderlich ist, um sie sinnvoll zu machen. Aber leider habe ich den Schnitt gemacht.
Doc Brown
Um ehrlich zu sein, wenn man so pingelig ist, "aber ein Zeiger ist buchstäblich nur eine Zahl", dann stimmt das auch nicht, eigentlich ist ein Zeiger ein Bezeichner, der eine Zahl referenziert;) Oder zumindest mussten wir die Sprachspezifikationen kennen, um in diese hineinzukommen Einzelheiten.
Zaibis
2
Ein Zeiger ist ein Wert (Zahl ist für einige Implementierungen bereits zu spezifisch), der möglicherweise auf ein Objekt verweist. Möglicherweise gibt es auch Nullzeiger, wilde Zeiger und baumelnde Zeiger, obwohl einige (oder sogar alle!) Von der verwendeten Sprache ausgeschlossen werden können.
Deduplicator
2
@ Deduplicator: Sie haben recht, aber ich denke, das mentale Modell eines Zeigers als Zahl ist gut genug für den Zweck dieser Frage. Also lassen Sie uns die Dinge einfach halten.
Doc Brown
5

Ich würde sicherlich nicht sagen, dass ein Zeiger ein Speicherort ist, der eine Adresse enthält. Zum einen kenne ich keine Architektur, 0x23453die in ein einzelnes Byte passen könnte. :) Auch wenn Sie die Byte / Wort-Unterscheidung von Hand wegwinken, haben Sie immer noch das Problem, dass jeder Speicherort eine Adresse enthält. Adressen sind nur Zahlen und der Inhalt des Speichers sind nur Zahlen.

Ich denke, der Trick dabei ist, dass "Zeiger" menschliche Absichten beschreibt , keine besonderen Merkmale der Architektur. Es ist ähnlich wie bei einem "Zeichen" oder einer "Zeichenfolge", dass man nichts Konkretes im Gedächtnis sieht - das sind alles nur Zahlen, aber sie funktionieren wie Zeichenfolgen, weil sie so behandelt werden. "Zeiger" bedeutet lediglich einen Wert, der als Adresse verwendet werden soll.

Um ehrlich zu sein, wenn Sie eine bestimmte Sprache unterrichten möchten (Ziel C?), Bin ich mir nicht sicher, ob das Herausziehen des klassischen Speicherbands überhaupt so nützlich ist. Sie lügen bereits, wenn Sie eingegebene Werte und Werte anzeigen, die für ein Byte zu groß sind. Lehren Sie Semantik, nicht Mechanik - die wichtigste Erkenntnis über Zeiger ist, dass sie Indirektion bieten. Dies ist ein äußerst nützliches Werkzeug, um dies zu verstehen.

Ich denke, ein guter Vergleich könnte eine URL sein, die Ihnen sagt, wo Sie einige Daten finden, aber nicht die Daten selbst. Lass mich ausreden:

  • Es ist Ihnen selten wichtig, wie die URL tatsächlich lautet . Die überwiegende Mehrheit von ihnen ist in Verbindung mit Namen verirrt. Viele Leute nutzen das Internet, ohne genau zu wissen, wie eine URL zu einer Seite führt. Manche Leute kennen URLs überhaupt nicht.

  • Nicht jeder String ist eine URL oder soll als URL verwendet werden.

  • Wenn Sie versuchen, eine gefälschte URL oder eine Seite aufzurufen, die zuvor vorhanden war, aber inzwischen gelöscht wurde, wird eine Fehlermeldung angezeigt.

  • Eine URL kann auf ein Bild, einen Text, eine Musik oder eine beliebige Anzahl anderer einzelner Elemente verweisen - oder auf eine Seite mit einer Vielzahl von Dingen, die darin enthalten sind. Es kommt sehr häufig vor, dass eine ganze Reihe von Seiten ähnliche Layouts, aber unterschiedliche Daten aufweisen.

  • Wenn Sie eine Webseite erstellen und auf Daten auf einer anderen Webseite verweisen möchten, müssen Sie nicht alles kopieren und einfügen. Sie können einfach einen Link dazu erstellen.

  • Beliebig viele andere Seiten können auf dieselbe URL verweisen.

  • Wenn Sie über eine Sammlung ähnlicher Seiten verfügen, können Sie eine Indexseite erstellen, auf der Links zu allen Seiten aufgeführt sind, oder Sie haben einfach einen "nächsten" Link am Ende von Seite 1, der Sie zu Seite 2 führt, und so weiter. Die Vor- und Nachteile beider Ansätze liegen auf der Hand, insbesondere wenn Sie überlegen, was der Webmaster tun muss, um Seiten an verschiedenen Stellen hinzuzufügen oder zu entfernen.

Diese Analogie macht sehr deutlich, wofür Zeiger sind , was für das Verständnis entscheidend ist - ansonsten wirken sie einfach willkürlich, kompliziert und sinnlos. Zu verstehen, wie etwas funktioniert, ist viel einfacher, wenn Sie bereits verstehen, was es tut und warum es nützlich ist. Wenn Sie bereits verinnerlicht haben, dass ein Zeiger eine Blackbox ist, die Ihnen sagt, wo sich etwas anderes befindet, und Sie dann die Feinheiten des Speichermodells kennenlernen, ist die Darstellung von Zeigern als Adressen ziemlich offensichtlich. Darüber hinaus können Ihre Schüler durch das Unterrichten von Semantik andere Formen der Indirektion besser verstehen und erfinden - was gut ist, wenn die meisten wichtigen Sprachen überhaupt keine Hinweise haben!

Eevee
quelle
every memory location contains an address- Jeder Speicherplatz hat eine Adresse. Es ist nirgendwo enthalten , außer vielleicht in einer Zeigervariable.
Robert Harvey
@RobertHarvey Jeder Speicherort (mindestens ein Wort) enthält eine Zahl, die trivial als Adresse interpretiert werden könnte . Der Punkt war, dass nichts in der Hardware tatsächlich Adressen von Nicht-Adressen unterscheidet
Eevee
2

Ich weiß, dass Sie bereits eine Antwort akzeptiert haben und diese Frage hat bereits fünf Antworten, aber es gibt einen Punkt, den sie nicht erwähnen. CS-Lehrbücher versuchen oft, bei der Wahl der Programmiersprache Agnostiker zu sein, was implizit zu der Annahme führt, dass die zur Beschreibung der Dinge verwendete Terminologie universell ist. Ist es nicht.

In C wird der Operator für unäres kaufmännisches Und der Operator "Adresse von" genannt. C-Programmierer würden ohne zu zögern sagen, dass der Ausdruck &xdie Adresse der Variablen x ergibt. Natürlich meinen sie "die Speicheradresse, in der der Wert der Variablen x gespeichert ist", aber niemand ist in gelegentlichen Gesprächen so umständlich. In C bezieht sich das Wort "Zeiger" normalerweise auf den Datentyp einer Variablen, deren Wert eine Speicheradresse ist. Oder gleichbedeutend mit dem Datentyp des Werts. Aber einige Leute würden "Zeiger" als Wert selbst verwenden.

In Java verhalten sich alle Variablen vom Typ Objekt oder Array ähnlich wie C-Zeiger (mit Ausnahme der Zeigerarithmetik), aber Java-Programmierer bezeichnen sie als Referenzen und nicht als Zeiger.

C ++ betrachtet Referenzen und Zeiger als unterschiedliche Konzepte. Sie sind verwandt, aber nicht ganz dasselbe, daher müssen C ++ - Programmierer die Unterscheidung in Gesprächen treffen. Das kaufmännische Und wird in einigen Kontexten als "Adresse von" und in anderen als "Verweis auf" gelesen.

Ein Zeiger ist eine Variable, deren Wert die Speicheradresse einer anderen Variablen ist.

So könnte es ein C-Programmierer beschreiben, der "einen Zeiger" im gleichen Sinne wie "ein Int." (Wie in "Ein Zeiger enthält eine Speicheradresse, während ein Int eine Ganzzahl innerhalb eines bestimmten Bereichs enthält.")

Ein Zeiger ist ein Speicherort, dessen Wert die Speicheradresse eines anderen Speicherorts ist.

Das ist eine merkwürdige Art, es zu sagen, weil es eine sehr lockere und informelle Definition von "ist" erfordert.

Ist es sicher zu sagen, dass eine Variable dasselbe ist wie ein Speicherort?

Es wäre klarer zu sagen, dass eine Speicheradresse der Ort im Speicher ist, an dem der Wert einer Variablen gespeichert ist. (Zugegeben, aufgrund von Compiler-Optimierungen werden nicht alle Variablen gespeichert, aber jede Variable, deren Adresse mit übernommen &xwird, wird gespeichert .)

gatkin
quelle
Wie wir pedantisch sind: Die Adresse, unter der etwas gespeichert ist. Abgesehen von einer Adresse, die nichts speichern kann, werden Dinge häufig an mehreren benachbarten Orten gespeichert, von denen nur einer (im Allgemeinen durch eine etwas konsistente Regel ausgewählt) adressiert wird (und nur eine von möglicherweise vielen Adressen verwendet).
Deduplizierer
@ Deduplicator Ich für meinen Teil versuche nicht pedantisch zu sein.
Gatkin
Der C-Standard unterscheidet sogar formal zwischen Variablen, die den Schritten der abstrakten Maschine an jedem „Sequenzpunkt“ genau folgen müssen - aus Gründen der Threadsicherheit und bestimmter Operationen auf niedriger Ebene auf Hardware mit Speicherzuordnung - und solchen, die nicht ausgeführt werden. t, die frei in ein Register verschoben oder komplett weg optimiert werden können.
Davislor
@Davislor: Der C-Standard verwendet den Begriff "Objekt" an Stellen, an denen andere Sprachspezifikationen "Variable" verwenden, sowie zur Beschreibung anderer Dinge, die keine Variablen sind. In einigen Diskussionen wird möglicherweise der sprachunabhängige Begriff "Variable" verwendet, aber aus irgendeinem Grund fehlt dem Standard ein Begriff zur Unterscheidung zwischen benannten disjunkten Zuordnungen (Variablen) und anderen Arten von Objekten wie verschachtelten Zuordnungen (Struktur- / Gewerkschaftsmitgliedern) oder den nicht benannten Objekten, die sich ergeben durch Dereferenzieren von Zeigern. Informell ist "Variable" ein großartiger Begriff, der vom Standard jedoch nicht verwendet wird.
Supercat
@supercat Das ist nicht richtig. Die C11 - Standard verwendet der Begriff „variable“ mehr als hundertmal, von denen einige Dutzenden sind Substantive, zB „Concurrent Zugriff auf die Variable initialisiert werden, auch über eine atomare Operation, stellt ein Datum Rennen.“
Davislor
1

Die Anweisung Ein Zeiger ist eine Variable, deren Wert die Speicheradresse einer anderen Variablen ist. Wenn ein Leser jedoch versteht, was genau ein Speicherort ist und wie er sich von einer Variablen unterscheidet, versteht er bereits, was genau ein Zeiger ist, und muss sich daher nicht mehr auf diese ungenaue Erklärung verlassen.

Die Anweisung Ein Zeiger ist ein Speicherort, dessen Wert die Speicheradresse eines anderen Speicherorts ist, ist falsch. Der Wert eines Zeigers muss nicht an einem Speicherort gespeichert werden, und es ist fraglich, ob ein Zeiger auf einen Speicherort zeigen muss, abhängig von der beabsichtigten Definition von "Speicher".

Was ist der Unterschied zwischen einer Variablen und einem Speicherort?

Ein Speicherort ist einer von mehreren möglichen Orten, an denen Daten gespeichert werden können. Diese Daten können eine Variable oder ein Teil einer Variablen sein. Variablen sind eine Möglichkeit, Daten zu kennzeichnen.

Peter
quelle
0

Diese Antwort konzentriert sich auf C und C ++. Das scheint angebracht, da sich Ihre Frage mit Zeigern befasst, die ein wesentlicherer Bestandteil von C / C ++ als von anderen Sprachen sind. Der Großteil dieses Beitrags gilt für die meisten kompilierten Sprachen ohne eine aufwendige Laufzeit (wie Pascal oder Ada, aber nicht wie Java oder C #).

Die bereits gegebenen guten Antworten betonen, dass eine Variable ein Sprachkonstrukt ist, das abstrakter ist als das physische Gedächtnis. Ich möchte jedoch betonen, dass diese Abstraktion eine bestimmte Begründung und ein bestimmtes System hat:

Die Abstraktion besteht hauptsächlich darin, einen Namen anstelle einer wörtlichen Adresse zu verwenden.

Die Grundidee ist, dass eine Variable ein benanntes Handle für ein typisiertes Objekt ist. Objekte in C / C ++ befinden sich normalerweise im Speicher. Die Sprachen fügen dann einige Feinheiten hinsichtlich des Lebensdauermanagements und des Datenmarshalls für Typkonvertierungen hinzu. Das Konzept von Variablen ist abstrakter als physikalische Adressen, da uns der numerische Wert von Adressen oder die genaue Position von Funktionen im Speicher nicht wichtig ist. Wir benennen sie einfach und adressieren sie später mit Namen, und der Compiler, der Linker und das Laufzeitsystem kümmern sich um die wichtigen Details.

Und tun Sie nicht so, als wäre C / C ++ speicherunabhängig: Es gibt schließlich den universell einsetzbaren Adressoperator. Ja, stimmt, Sie können die Adresse einer C-Variablen in der Registerspeicherklasse nicht übernehmen. aber wann hast du zuletzt eins benutzt? Dies ist eine besondere Ausnahme vom allgemeinen Konzept und keine pauschale Ablehnung des Arguments. Die allgemeine Regel ist im Gegenteil, dass das Aufnehmen einer Adresse einer Variablen den Compiler tatsächlich dazu zwingt, ein Objekt im Speicher zu erstellen, auch wenn dies sonst nicht der Fall wäre (z. B. mit Konstanten). Das "named handle" -Konzept ist auch ein gutes Paradigma für C ++ - Verweise: Ein Verweis ist nur ein anderer Name für dasselbe Objekt.

Als ich Inline Assembler für 68k geschrieben habe, war es schön zu sehen, wie Sie Variablennamen als Offsets für Adressregister verwenden können (und Sie können die Namen von deklarierten Variablen registeranstelle der Bare-Metal-Registernamen verwenden!). Für den Compiler ist eine Variable ein konstanter Adressoffset. So wiederholen Sie: Variablen werden als Handles bezeichnet, normalerweise für Objekte im Speicher.

Peter - Setzen Sie Monica wieder ein
quelle
Zeiger sind ein sehr grundlegender Bestandteil von C #, Java, JS und anderen Sprachen. Wenn man sie anders nennt, ändert das nichts, obwohl es eine gute PR ist.
Deduplizierer
@ Deduplicator :-) Gute alte Tony ...
Peter - Wiedereinsetzung Monica
0

Es hört sich so an, als ob die Frage auf eine populäre Sprache abzielt, die durch die Erweiterung des C-Standards mit der zusätzlichen Garantie "gebildet wird dominiert der erstere Teil. "sowie eine Definition von" Variable ", die mit der Verwendung des Begriffs durch andere Sprachen übereinstimmt.

In dieser Sprache kann jeder Speicherort als eine nummerierte Mailbox angesehen werden, die immer eine Anzahl (typischerweise acht) von Bits enthält, von denen jedes unabhängig null oder eins sein kann. Speicherorte sind typischerweise in Reihen von zwei, vier oder acht organisiert. und einige Operationen verarbeiten mehrere aufeinanderfolgende Speicherstellen gleichzeitig. Abhängig von der Maschine können einige Operationen, die mit Gruppen von zwei, vier oder acht Speicherplätzen arbeiten, auf Positionen innerhalb einer einzelnen Zeile beschränkt sein. Während einige Computer möglicherweise einen einzelnen Raum mit fortlaufend nummerierten Postfächern haben, können andere mehrere nicht zusammenhängende Gruppen mit nummerierten Postfächern haben.

Eine Variable identifiziert einen Bereich von Speicherorten, die ausschließlich ihr zugeordnet sind, und einen Typ, als den diese Speicherorte interpretiert werden sollten. Das Lesen einer Variablen bewirkt, dass die Bits in ihren zugeordneten Speicherorten in einer dem Variablentyp entsprechenden Weise interpretiert werden, und das Schreiben einer Variablen bewirkt, dass die zugeordneten Bits in einer dem Typ und Wert entsprechenden Weise gesetzt werden.

Eine Adresse kapselt alle Informationen, die zur Identifizierung eines Postfachs erforderlich sind. Dies kann als einfache Nummer oder als eine Art Gruppenbezeichnung zusammen mit der Nummer einer Mailbox in dieser Gruppe gespeichert werden.

Wenn Sie den &Operator auf eine Variable anwenden, erhalten Sie einen Zeiger, der die Adresse und den Typ der Variablen enthält. Das Anwenden des unären Operators *oder []Operators auf einen Zeiger bewirkt, dass die Bits von Postfächern, die an einer gekapselten Adresse beginnen, in einer dem gekapselten Typ entsprechenden Weise interpretiert oder festgelegt werden.

Superkatze
quelle
Es klingt, als ob Sie die Frage überdenken.
Robert Harvey
0

Ich komme zu spät zu dieser Party, aber ich kann nicht widerstehen, meine 2 Cent in.

Was ist zu diesen Zeiten der Unterschied zwischen den in diesen Speicherorten gespeicherten Werten?

Zeit 1

Bildbeschreibung hier eingeben

Zeit 2

Bildbeschreibung hier eingeben

Richtige Antwort: nichts. Sie sind alle identische Werte, die mit unterschiedlichen Interpretationen ihrer Bedeutung dargestellt werden.

Woher weiß ich das? Weil ich derjenige bin, der das erfunden hat. Das weißt du noch nicht so genau.

Sie stoßen auf etwas, das ich als Out-of-Band- Problem bezeichne. Wie die Bedeutung dieser Werte richtig interpretiert wird, wird hier nicht gespeichert. Dieses Wissen wird woanders gespeichert. Wenn Sie diese Werte jedoch auf Papier präsentieren, geben Sie diese Interpretation ein. Das heißt, Sie haben Informationen hinzugefügt, die an diesen Speicherorten einfach nicht vorhanden sind.

Zum Beispiel sind die Werte hier identisch, aber Sie wissen nur, dass es wahr ist, wenn Sie richtig sind, wenn Sie annehmen, dass eine ASCII / UTF-8-Zeichenkodierung so ist, wie ich die erste erhalten habe, anstatt EBCDIC zu sagen . Und Sie müssen auch davon ausgehen, dass es sich bei dem zweiten Wert um hexadezimale Ausdrücke der an diesen Speicherorten gespeicherten numerischen Werte handelt, die alle Zeiger auf andere Adressen sein können, anstatt Verweise auf Zeichenfolgen zu verwenden, die alle mit "0x" beginnen. : P

Nichts, was an diesen Speicherorten gespeichert ist, sagt Ihnen, dass eine dieser Annahmen richtig ist. Diese Informationen können gespeichert werden. Aber es würde woanders gelagert werden.

Dies ist das Präsentationsproblem . Sie können überhaupt keine Zahl ausdrücken, ohne sich vorher darauf geeinigt zu haben, wie sie präsentiert werden soll. Sie können sich auf Annahmen, Konventionen und den Kontext stützen. Wenn Sie jedoch tiefgreifend voranschreiten und die Präsentation nicht explizit definiert ist, ist die einzig richtige Antwort "nicht genügend Informationen".

kandierte_orange
quelle
Es macht noch mehr Spaß, wenn derselbe Speicher gleichzeitig für verschiedene konstante Dinge verwendet wird.
Deduplizierer
@ Deduplicator True. Das erinnert mich immer an die Neuinterpretation von c ++ . Gleiche Teile anders gesehen.
candied_orange
@ Deduplicator oder, um es sich
vorzustellen