Was ist eine schöne Erklärung für Zeiger? [geschlossen]


72

Hatten Sie in Ihrem eigenen Studium (allein oder für eine Klasse) einen "ah ha" -Moment, in dem Sie die Hinweise wirklich verstanden haben? Haben Sie eine Erklärung, die Sie für Anfängerprogrammierer verwenden, die besonders effektiv zu sein scheint?

Wenn zum Beispiel Anfänger zum ersten Mal auf Zeiger in C stoßen, können sie einfach &s und *s hinzufügen, bis sie kompiliert sind (wie ich es selbst einmal getan habe). Vielleicht war es ein Bild oder ein wirklich gut motiviertes Beispiel, das Zeiger für Sie oder Ihren Schüler zum "Klicken" brachte. Was war es und was hast du versucht, bevor es nicht zu funktionieren schien? Waren Themenvoraussetzungen (z. B. Strukturen oder Arrays)?

Mit anderen Worten, was war notwendig, um die Bedeutung von &s zu verstehen und *wann Sie sie mit Zuversicht verwenden konnten? Das Erlernen der Syntax und Terminologie oder der Anwendungsfälle reicht nicht aus. Irgendwann muss die Idee verinnerlicht werden.


Update: Ich mag die Antworten so weit; Bitte lass sie kommen. Hier gibt es viele großartige Perspektiven, aber ich denke, viele sind gute Erklärungen / Slogans für uns, nachdem wir das Konzept verinnerlicht haben. Ich bin auf der Suche nach den detaillierten Zusammenhängen und Umständen, als es Ihnen dämmerte.

Zum Beispiel:

In C verstand ich Zeiger nur ein wenig syntaktisch. Ich hörte zwei meiner Freunde, die Zeiger einem anderen Freund erklärten, der fragte, warum a structmit einem Zeiger übergeben wurde. Der erste Freund sprach darüber, wie es referenziert und modifiziert werden musste, aber es war nur ein kurzer Kommentar des anderen Freundes, bei dem es mir auffiel: "Es ist auch effizienter." Das Übergeben von 4 Bytes anstelle von 16 Bytes war die letzte konzeptionelle Verschiebung, die ich brauchte.


16
'Shotgun'-Methode: Wirf * s überall hin, bis es funktioniert.
Michael K

15
@Michael: Ja, viel Glück damit.
Robert Harvey

8
Diese Frage stellt sich kurz zu Beginn jedes Semesters auf SO. Die neueste Inkarnation ist hier: stackoverflow.com/questions/4118647/…
Tim Post

10
Was ist eine schöne Erklärung für Zeiger? Brian Kernhigan und Dennis Ritchie hassen Software-Ingenieure.
Adam Crossland

3
Es hat für mich "geklickt", nachdem ich einige Zeit mit dem Einzelschritt-Code im Debugger verbracht hatte. Ja, ich war mit den Grundlagen der Computerarchitektur vertraut - ich habe Assemblierung auf Commodore 64 gelernt, und danach war x86 ASM ziemlich unkompliziert. Also kannte ich das Konzept einer "Adresse" bereits, ich verstand nur nicht, wie es auf die syntaktischen Konstrukte von C abgebildet wurde.
zvrba

Antworten:


25

Memory-as-a-Grid-Diagramm

Normalerweise stelle ich das Gedächtnis als "Gitter" dar, so dass ich Adressen erfinden, verschiedene Speicherbereiche hervorheben und in die Zellenwerte (oder noch weiter in ihre binären Darstellungen) schreiben und die Zeiger im Gedächtnis mit den Werten verknüpfen kann, die sie haben zeigen auf. (Und dann noch erwähnen, dass es eine Vereinfachung ist).

Normalerweise ist es für die meisten meiner Schüler ein "ohhhh" Moment.

Symbol Jonglieren

Wenn sie dann aufhören, die Verwendung von & und * zu vergessen, ist es ganz einfach: Präsentieren Sie sie auf dieselbe Weise, wie sie mathematische oder physikalische Berechnungen durchführen. Wenn Sie eine Entfernung in km durch eine Zeit in Stunde teilen, erhalten Sie eine Geschwindigkeit in km / h. Was drin ist, muss draußen sein. Einfach.

printf zur Rettung

Nur ein paar grundlegende Beispiele zu machen, die visuell darstellen, was Sie mit diesen erklärt haben, wird sie in dem trösten, was sie zu verstehen glauben, oder ihnen die Gelegenheit geben, zu sagen, "ah, ich verstehe das nicht".

Seien Sie umfangreich

Behandeln Sie Zeiger für einfache Typen und stellen Sie sicher, dass sie den Unterschied zwischen der Adressierung und der Größe eines Datentyps verstehen, sowie Strukturen, Arrays und mehrere Ebenen.

Starten Sie dann die Zeigerarithmetik.


Anhang: Rekursion

Normalerweise erkläre ich Rekursionen auf ähnliche Weise anhand einer visuellen Darstellung. Lassen Sie sie das Alphabet mit einer vorgefertigten Funktion drucken, die ein einzelnes Zeichen schreibt, und bitten Sie sie dann, es in umgekehrter Reihenfolge zu drucken, indem Sie nur zwei Zeilen ändern.

Normalerweise gibt es ein "Was zum ...?" Moment, und wenn Sie Ihrem printf nur einen weiteren Parameter hinzufügen, um numerische Werte zu drucken und die Schritte einzurücken, wird dies zu einem erleichterten Seufzer.


Alternativen: Das Play-Doh-Modell und die Wasserbecher

Ich hatte tatsächlich einige Kollegen an einer Universität, die den Studenten ein Video zeigten, in dem Zeiger und Speicherzugriffe mit Play-Doh-Paste erklärt wurden. Es war unglaublich clever und gut gemacht, obwohl ich diese Technik selbst nie wirklich angewendet habe, außer bei sehr jungen Lernenden, die daran interessiert waren, Programmieren zu verstehen (aber normalerweise würde ich sie nicht zu früh mit Hilfe von Zeigern zu einer Sprache führen). Grundsätzlich werden winzige Bälle aus play-doh verwendet, die Sie an andere größere Bälle aus play-doh anhängen können, die Speicherbereiche darstellen, und die Sie kombinieren können, um sie entweder zu verknüpfen (wie in einer verknüpften Datenstruktur) oder zusammenzuführen (wie in einer zusammenhängenden Struktur) Speicherplatz). Das Verwenden verschiedener Farben für die Speicherbereiche, auf die verwiesen wird, und die Zeiger helfen ebenfalls. Aber ich denke immer noch, dass das Memory-as-a-Grid-Ding besser funktioniert, wie Sie deutlich zeigen können, handelt es sich bei dem Zeigen wirklich um "Adressieren", wie auf einer "Karte / einem Raster". Während der Play-Doh-Modus sie immer noch verwirrt zu denken, dass sich die Dinge im Gedächtnis wirklich berühren.

Die Sache mit dem Wasserbecher wurde auch direkt von einer Kollegin benutzt, aber ich weiß nicht, ob sie darauf gekommen ist. Es war ein interessanter Ansatz, aber ich bemerkte, dass viele Schüler von der Erklärung verwirrt waren. Etwas, das der DevSolo-Kaffeetassentechnik ähnelt . Aber ich denke, es ist tatsächlich irreführend, da Sie die Schüler dazu bringen, Container, Datenstrukturen, Zeiger und Arrays zu verwechseln. Ich nehme an, dass es ein interessanter Ansatz ist, Arrays am Anfang zu erklären, aber ich würde mich nicht lange daran halten.


Wow, danke für das Kopfgeld. Ich bin froh, dass die Antwort geschätzt wurde.
Haylem

Ziehen Sie es heraus: | das klingt nach gutem unterricht!
Gespenster

80

Jemand viel weiser als ich einmal sagte:

Die Nonne Wu Jincang fragte den sechsten Patriach Huineng: "Ich habe das Mahaparinirvana-Sutra viele Jahre lang studiert, aber es gibt viele Bereiche, die ich nicht ganz verstehe. Bitte klären Sie mich auf."

Der Patriach antwortete: "Ich bin Analphabet. Bitte lesen Sie mir die Zeichen vor, und vielleicht kann ich die Bedeutung erklären."

Die Nonne sagte: "Sie können nicht einmal die Zeichen erkennen. Wie können Sie dann die Bedeutung verstehen?"

"Wahrheit hat nichts mit Worten zu tun. Wahrheit kann mit dem hellen Mond am Himmel verglichen werden. Wörter können in diesem Fall mit einem Finger verglichen werden. Der Finger kann auf die Position des Mondes zeigen. Der Finger ist jedoch nicht derjenige." Mond. Um auf den Mond zu schauen, muss man über den Finger schauen, oder? "


13
+1 für die Dereferenzierung des Mondes. +1 für die Koan, wenn ich könnte.
Tim Post

14
Was ist der Klang von einem Finger, der abstimmt?
Adam Crossland

3
@Adam hängt davon ab, ob Sie eine Maus oder ein Trackpad verwenden.
Daniel Joseph

7
@ Frank Es war ein tolles Zitat. Dennoch denke ich, dass es nicht helfen wird, die Idee zu begreifen. Speziell für jemanden, der neu im Umgang mit Zeigern ist.
Gulshan

11
Dies ist eine wunderschöne Geschichte ... aber ich vermute, dass die Leute deswegen abstimmen, anstatt dass sie die Hinweise gut erklären.
Kyralessa

46

Ich fand, dass Diagramme sehr hilfreich waren. Beispiel:

Zeigerdiagramm


Diese Art von Diagramm hat mir gezeigt, dass Zeiger ihre eigene Variable sind, aber einen Wert enthalten, der die Position eines anderen Objekts, dh eines Arrays oder einer Zeichenfolge, darstellt. Wenn ich mit Bleistift fertig bin, kann ich mein Programm auch auf Papier oder auf einer Tafel / Whiteboard nachzeichnen.


4
Entweder sollte der Wert in "pointer" 4 sein, oder die Array-Indizes (oder Speicheradressen) sollten bei 0 beginnen. Wie kann sonst ein Zeiger, der den Wert 3 enthält, auf Position 4 zeigen?
MAK

++ Genau so wollte ich es erklären. Ich habe in Fortran angefangen (zum Guten oder Schlechten!). In Fortran verwendeten wir damals parallele Arrays anstelle von Arrays von Strukturen (keine neuen ). Wenn ein Array einen Index für "eine andere Zeile" in den Arrays enthielt, haben wir ihn als "Zeiger" bezeichnet, und das war aufregend. Wir haben verknüpfte Listen erstellt, Bäume, wie Sie es nennen.
Mike Dunlavey

2
Ich finde Zeiger am besten erklärt mit Bildern, die angeben, was wo gespeichert ist, und Pfeilen, um anzugeben, wo Zeiger zeigen.
Gablin

32

Als ich zum ersten Mal etwas über Zeiger "lernte", stieß ich darauf. Meine Universität hatte die Entscheidung schon lange getroffen, bevor ich mich einschrieb, um den Lehrplan auf Java zu konzentrieren. Als mein Professor für Datenstrukturen eine Vorlesung über C hielt und uns aufforderte, eine XOR-Liste mit Hinweisen zu implementieren, hatte ich das Gefühl, etwas zu lernen weit über meinen Kopf.

Ich habe die Definition verstanden:

Ein Zeiger ist eine Variable, die eine Adresse einer Variablen enthält

Trotzdem habe ich einen großen Teil des Konzepts nicht verstanden. Rückblickend denke ich, dass es um drei Dinge ging:

  1. Was genau ist ein Speicherort? (Zu der Zeit habe ich keinen Computer Organization Kurs belegt)

  2. Die umständliche Syntax (Also ähm ... warum genau ist es wie "int * ip" definiert, aber anschließend beziehe ich mich auf die Variable als "ip"?)

  3. Wie genau ist es vorteilhaft, die Adresse einer Variablen zu speichern, anstatt nur die Variable zu verwenden?

Erst als ich das K & R-Buch kaufte und jedes Problem erledigte, bekam ich wirklich ein Gespür für Hinweise. Abgesehen von der Tatsache, dass ich den Computer Organization-Kurs schon lange abgeschlossen hatte (was meiner Meinung nach vor dem Erlernen von C erforderlich sein sollte), hing ein Teil davon mit der Tatsache zusammen, dass ich erkannte, dass Zeiger für Funktionen, Arrays, Strukturen ... verwendet werden können. nützliche Dinge zu tun und nicht nur als Speicher für Adressen von gewöhnlichen Variablen.

Aber mein "Aha" -Moment war bei weitem die Art und Weise, wie K & R die umständliche Syntax der Definition eines einfachen Zeigers erklärte. Ich habe im gesamten Buch Notizen gemacht (in denen ich die vom Buch gemachten Punkte in meine eigenen Worte umformuliere, um mein Verständnis zu fördern), und dies ist diejenige, die sich darauf bezieht:

Ein Zeiger ist eine Variable, die eine Adresse zu einer Variablen enthält. Ein Zeiger wird mit dem Operator '*' definiert und dereferenziert (was den Wert ergibt, der an dem Speicherort gespeichert ist, auf den er zeigt). der Ausdruck ist mnemonisch.

Ex.: 
   int a;      /* Variable 'a' is an integer */

   int *ip;   /* Variable ip is a pointer and dereferencing it gives an integer.
                 In other words, the expression *ip is an int, so ip is a pointer
                 to an int */

Ich hatte immer das Gefühl, dass ich die fortgeschritteneren Konzepte von Zeigern nicht vollständig erfassen konnte, bis ich etwas so Grundlegendes in meinem Kopf hatte. Es hatte mich nach dieser Aufgabe endlos gestört (was ich übrigens nicht so gut gemacht habe;)), warum "* ip" nicht existierte, nachdem ich "* ip" definiert hatte. Dies zu beherrschen ist wesentlich für fortgeschrittenere Konzepte, die Zeiger wie Funktionszeiger und kompliziertere Definitionen wie diese beinhalten:

char (*(x())[])()

Alles in allem denke ich, dass das Konzept der Zeiger Folgendes erfordert:

  1. Grundlegendes Verständnis, wie Speicher in einem Computer angeordnet ist (und was Speicher ist).

  2. Wissen, wie mächtig Zeiger sein können (Verwendung in der realen Welt, nicht nur ein weiteres abstraktes Konzept, das sie zum Zweck des Lernens lernen).

  3. Entschlüsselung der umgangssprachlich als "Definition eines Zeigers" bekannten Hieroglyphen

Alles in allem denke ich, dass es mindestens 3 "Aha" -Momente geben sollte, wenn man etwas über Zeiger lernt. Ich bin noch ein Student, also dachte ich, du würdest die Sichtweise von jemandem schätzen, der noch (relativ) jung ist, das Konzept zu lernen.


+1 für die 3 "Ah ha!" monents. Groking Zeiger kommt in Schichten. Ich "verstand" Punkte für eine lange Zeit, bevor mir klar wurde, dass ich nur ungefähr die Hälfte von Zeigern verstand :)
Binary Worrier

Ich denke, Sie haben völlig Recht, dass ein sehr großer Teil des "Nichtverstehens von Zeigern" tatsächlich auf die seltsame C-Syntax abfällt. [Denkt: Ich frage mich, wie schwierig es sein würde, mit dieser Art von SyntaxPointerTo<int> a
umzugehen

Einverstanden, @Benjol. Ich bin überrascht, dass die Syntax int* ipnicht üblicher ist. Ich fing endlich an, Zeiger zu verstehen, als ich Code sah, der so formatiert war. Dann könnte ich es lesen als "IP ist vom Typ Int Zeiger."
Jacob

19

Zeiger sind ein bisschen wie die Anwendungsverknüpfungen auf Ihrem Desktop. Löschen Sie die Verknüpfung, und das Ziel ist noch vorhanden. Starten Sie die Verknüpfung und das Ziel wird gestartet.

Ich erkläre die Funktionsweise immer, indem ich einfach eine txt-Datei auf meinem Desktop und zwei Verknüpfungen zu der Datei erstelle. Nachdem Sie die Verknüpfungen kopiert und gelöscht haben, können Sie sehen, dass die Leute die Idee hinter "Referenzen" verstehen.

Sobald die Gruppe die Grundlagen der Verknüpfungen verstanden hat, können Sie Zeiger erläutern, wie Sie möchten. Sie werden es wahrscheinlich ziemlich leicht verstehen.


Das ist keine schlechte Analogie. Nur ein paar Punkte für jeden, der dies wörtlich als "fester Link" bezeichnet, zeigen immer auf das Ziel, auch wenn das Verzeichnis geändert wird. Ein Zeiger zeigt auf den ursprünglichen Speicher, auch wenn das Objekt verschoben wurde. Ein "fester Link" teilt Ihnen mit, wenn das Ziel nicht mehr vorhanden ist. Ein baumelnder Zeigerzeiger sollte auf NULL gesetzt werden.
Snmcdonald

Ein fester Link ist wie ein Smart Pointer mit Referenzzählung
jk.

1
+1. Eine der besten praktischen Analogien zur Erklärung von Hinweisen. Ich bin mir sicher, dass die Schüler sofort auf die Idee kommen werden, da diese Funktionalität von allen am häufigsten verwendet wird.
Karthik Sreenivasan

13

Vor 8-10 Jahren unterrichtete ich an einem Community College einen Einführungskurs "C". Dies war immer ein lustiges Thema zu erkunden. Was am besten zu funktionieren schien, war, nach ein paar Gesprächen mit einem Kollegen, eine Kaffeetasse und Ihre Hand zu benutzen.

Ich habe die Analogie einer Kaffeetasse (oder einer Reihe davon für Arrays) als Variable verwendet (sie kann etwas enthalten). Ich benutzte dann meine Hand, die auch etwas halten konnte, oder streckte meinen Zeigefinger aus, um auf eine Kaffeetasse zu zeigen.

Eine nahe Hand war null, ein Finger, der auf meinen Kopf zeigte (wie eine Scheinwaffe), war ein baumelnder Zeiger.

Dann mit ein paar Demonstrationen und Reisen durch den Debugger, es hat mit den meisten geklickt.


3
Du hast mich schon verwirrt.
kirk.burleson

1
@ Kirk, wie so? Lass mich sehen, ob ich es klären kann.
DevSolo

4
++ Es gibt nichts Besseres als zu lehren, um über diese Dinge nachzudenken.
Mike Dunlavey

Einer meiner Dozenten an der Universität tat etwas Ähnliches, indem er Studenten (einer von ihnen war "Niel", für zusätzliches Lachen) anstelle der Kaffeetasse verwendete. Handgewellt auf das Publikum zu zeigen, war ein baumelnder Zeiger, weil er auf alles zeigen konnte.
Kaz Dragon

2
Ein baumelnder Zeiger ist eher so, als würde er auf Neil zeigen und ihn dann dazu bringen, seinen Stuhl zu verlassen, ohne zu ändern, wohin er zeigt. Dann wird versucht, diesem Zeiger zu folgen und das, was Sie dort finden, als Neil zu interpretieren, unabhängig davon, wer dort gelandet ist.
Jon Purdy

10

Ich mache mir wirklich große Sorgen, wenn ich die Frage "Wie haben Sie die Hinweise verstanden?" Höre. Ich fand das Konzept immer unglaublich einfach und eine logische Weiterentwicklung der Sprachen, die den Programmierern eine große Macht verleiht.

Was mich beunruhigt, ist, dass es mir nie schwer gefallen ist, das Konzept von Zeigern zu verstehen. Also, wenn Sie hier "wann haben Sie es endlich bekommen" immer und immer wieder, beginnen Sie zu denken:

Verstehe ich es wirklich? Vielleicht habe ich das nie getan?

Vielleicht liegt der Grund, warum das Konzept schwierig zu sein scheint, darin, dass wir allen, die noch nicht auf sie gestoßen sind, immer wieder sagen, dass Zeiger so schwierig sind, und hier sind hundert Möglichkeiten, wie Sie lernen können?

Wenn ich diese Idee einfach da rausschmeiße, liebe ich natürlich persönlich ein gutes Diagramm und Steve Gibson macht immer einen fantastischen Job darin, irgendetwas zu erklären !


Interessant ... welche Sprache haben Sie damals benutzt? Ich denke, dass die C-Syntax eine Menge Leute auslöst. Wenn Sie zuerst die Montage wüssten, könnte ich das als einen Grund ansehen. [Übrigens, ich möchte dies abstimmen, aber ich habe heute meine
Obergrenze

Interessanterweise hatte ich lange Zeit keine Kenntnis von "gefährlichen" Zeigern und arbeitete in Python (und Java an der Universität). Dann nahm ich ein "objektorientiertes Methoden" -Modul, das C ++ als die Sprache der Wahl verwendete, und tauchte direkt dort ein.
Marcus Whybrow

Ich denke auch, dass es definitiv hilfreich sein kann, zu verstehen, wie ein Programm im Gedächtnis dargestellt wird, aber ich würde eher sagen, dass es der effektivste Aspekt ist, zu verstehen, warum Zeiger eine nützliche Ergänzung zu einer Sprache waren, da Sie dasselbe durchmachen Prozess wie die ursprünglichen Designer.
Marcus Whybrow

+1 Ich habe keine Ahnung, warum die Leute Zeiger für schwierig oder mysteriös halten.
ggambett

Ja, Zeiger waren schon immer so offensichtlich einfach und nützlich, dass ich mir nicht vorstellen kann, dass etwas "Schwieriges" an ihnen ist. Ich hasse es, wenn ein Lehrer eines Kurses sagt "Jetzt ist das ein bisschen schwierig", weil es einfach so subversiv ist. Lehren Sie einfach das verdammte Zeug und lassen Sie die Schüler selbst entscheiden, ob sie es für schwierig halten.
Jon Purdy

7

Ich hatte nie große Probleme mit Zeigern in C, aber das mag daran liegen, dass ich zuerst Assembler lernen musste. Eigentlich war es eine Erleichterung, Adressen nicht mehr selbst verwalten zu müssen. Vielleicht ist die Antwort (vorausgesetzt, Sie unterrichten dies), den Schülern eine emulierte Assemblersprache zu geben, mit der sie arbeiten können. Sie werden es herausfinden, wenn sie etwas Raffinierteres als "Hallo Welt" schreiben.


+1 zum Anpassen einer primitiveren Abstraktion, anstatt zu versuchen, eine Analogie zu verwenden.
Anonymous Type

In meiner Highschool widmete sich eine Einheit der Informatik dem Studium eines Streichholzschachtelcomputers , der von der Tafel aus unterrichtet werden kann, ohne jemals einen echten Computer zu berühren oder einzubeziehen.
rwong

@ Larry Coleman, Versammlung !!!!!!!!!!! Ich möchte es zuerst vor C versuchen. Bitte sagen Sie mir, wo ich anfangen soll zu lernen. Kostenlose Ebooks, kostenlose PDF? IDE? Bitte!!!!!!!!!!!!!!!!!!!
Spacez Ly Wang


6

Wie habe ich wirklich von Zeigern erfahren? Durch das Schreiben eines einfachen Compiler-Studienanfängers.

Wie erklärt man Hinweise in Laienbegriffen? Ich mag die (datierte?) Analogie eines Bibliothekskatalogs, der auf Karteikarten gespeichert ist. Jede Karte ("Zeiger") enthält Informationen darüber, wo sich ein Buch ("Daten") befindet, enthält jedoch nicht das Buch selbst. Wenn Sie die Karte ändern ("Zeigerarithmetik"), ändert sie lediglich das Buch, auf das sie zeigt, und hat keine Auswirkungen auf das Buch selbst. Achten Sie nur darauf, die Adresse nicht zu verfälschen, oder Sie verweisen möglicherweise auf ein nicht vorhandenes Buch oder sogar die falsche Bibliothek. Wenn Sie jedoch der "Adresse" auf der Karte folgen und zum richtigen Teil der Bibliothek gehen ("den Zeiger dereferenzieren"), können Sie das Buch selbst sehen / ändern.


+1 für die Erinnerung an meinen CS-Kurs, in dem ich genau diese Erklärung hatte
Gary Rowe

Das ist in gewisser Hinsicht gut, aber etwas irreführend, da die Karten nicht wirklich sagen, wo sich das Buch befindet. Sie müssen noch einen sneaker-orientierten Suchalgorithmus ausführen. Möglicherweise modelliert dies eine Datenbank besser, indem auf ein gespeichertes Objekt durch einen Schlüssel (Rufnummer) verwiesen wird.
DarenW

+1 Die Analogie behält das gleiche Konzept wie das von Barfieldmv erklärte bei, jedoch mit einem realistischeren Ansatz.
Karthik Sreenivasan

5

Ich gehe davon aus, dass jemand, der Zeiger lernen möchte, weiß, was die normalen Variablen sind und wie sie in C funktionieren. Nun wollen wir versuchen, Zeiger mit einigen ihrer Attribute zu definieren.

  • Sie sind auch Variablen, aber unterschiedlicher Natur. Angenommen, der variable Raum enthält zwei Ebenen. Die normalen Variablen verschiedener Typen befinden sich in der oberen Ebene und die Zeiger in der unteren Ebene. Wie diese Figur-

    Alt-Text

  • Wie der Name "Pointer" andeutet, können Zeiger auf etwas zeigen. Als ob unser Finger auf ein Objekt zeigen könnte. Auf was deuten sie hin? Dies sind die normalen Variablen. Kurz gesagt, "Zeiger zeigen auf normale Variablen".

  • Wie normale Variablen haben auch Zeiger die gleiche Anzahl von Typen wie int, char oder float. Ein Zeiger eines bestimmten Typs kann nur auf den gleichen Variablentyp verweisen.
  • Ein Zeiger kann auf eine Variable zeigen und später kann derselbe Zeiger auf eine andere Variable zeigen. Nur der Typ sollte gleich sein. Die Zuordnung eines Zeigers zu einer Variablen ist also nicht permanent und kann geändert werden.
  • Wie wird ein Zeiger deklariert? Fast wie normale Variablen. Sie müssen dem Namen ein Sternchen ( *) voranstellen . Mögen-

    int *pointer;
    
  • Wie wird dann ein Zeiger einer Variablen zugeordnet? Verwenden Sie den &Operator vor der Variablen wie diese Anweisung.

    pointer = &variable;
    
  • Wie wird ein Zeiger verwendet, wenn auf eine Variable gezeigt wird? Dies geschieht auch, indem dem Namen ein Sternchen ( *) vorangestellt wird . Dann kann es anstelle der Variablen verwendet werden, auf die es jetzt zeigt.

    *pointer = var1 + var2;
    

    Anstatt von

    variable = var1 + var2;
    
  • Spielen Sie jetzt mit Zeigern mit etwas Code. Gewöhnen Sie sich jetzt einfach an diese Eigenschaften von Zeigern. Bis zu diesem Punkt sprechen wir darüber, was Zeiger tun. Sobald Sie damit einverstanden sind, beginnen Sie zu untersuchen, wie Zeiger auf eine Variable zeigen und wie sie reagieren, wenn normale arithmetische Operationen auf sie angewendet werden. Gehen Sie dann für die Beziehung zwischen Zeigern und Arrays und Zeigern auf Zeiger.

Das ist alles, was ich über das Lernen von Zeigern vorschlagen werde.


Ich wollte "zuerst verfolgen, was es dann wie macht". Abstraktion!
Gulshan,

5

Bearbeitet zur Unterstützung der überarbeiteten Anforderung der Frage

Mein Weg zum "Post-Pointer" -Verständnis (wenn ich mich richtig erinnere) ging so. Ich hatte einige einfache Erfahrungen mit der Assembler-Programmierung, als ich noch mit einem BBC Micro rumgespielt habe, also hatte ich das Konzept des Speichers als einen Haufen Kisten (siehe unten). Dies wurde durch die Verwendung von Arrays verstärkt. Ich ging jedoch in die Welt von C und musste mich mit Strings auseinandersetzen, was Zeiger bedeutete. In BASIC war das trivial, in Assembler musste ich nie damit arbeiten, und jetzt in Classic C sind es alles Zeiger und so. Ah, aber ich kann zu Arrays mit (nullterminierten) Strings wie folgt zurückkehren:

char s[] = "Hello, world!";
printf("%s",s);

Schön und gut, das ist nur eine Reihe von Zeichen (8 Bit pro Zeichen in meiner kleinen Welt) mit einem Null-Zeichen am Ende, um zu zeigen, wo es endet. Das printf nimmt nur dieses Array und überläuft es beim Drucken. Aber was ist, wenn ich diesen String in eine Funktion übergeben möchte?

void print_str(char* p) {
  printf("%s",p);
}

Ist das, was in der Bedienungsanleitung steht, aber worum geht es dabei? Hmm, char * bedeutet "Zeiger auf ein Zeichen". OK ... hat mich verloren. Dann wurde mir klar, dass das Zeichen * p gleich s [0] macht. OK, ich kann das benutzen, aber ich habe immer noch nicht herausgefunden, was Zeiger sind. Ich meine, wie setze ich einige Daten mit einem dieser Dinge? Wieder ab ins Handbuch ...

char* p = "Hello World!";

Während ich das Obige schreibe, sage ich mir "deklariere einen Zeiger auf ein Zeichen und setze ihn gleich diesem Array von Zeichen". Irgendwie macht dieser Zeiger ein Array überflüssig. Vermutlich ist es der Compiler, der zur Abwechslung ein paar Sachen für mich macht. Wie kann ich das Array mit diesem Zeiger ändern? Ich weiß, dass ich die Reihenversion benutzen könnte

 s[2] = 'L'; 

aber was ist das Äquivalent in "Zeiger sprechen"? Auf zu diesem Handbuch ...

*(p+2) = 'L';

Ich nehme an, dass * einfach "der Inhalt der Speicheradresse" bedeutet und (p+2)ist s[2]. Was bedeutete, dass der Zeiger p ... nur ... eine ... Adresse ... Bong war!

Dass es den Klang der Erleuchtung gibt. Ich habe plötzlich Zeiger gezwitschert (es ist lange her, wir Oldtimer "grockten" erst später). Es war nur eine Indirektion.


Original:

OK, mein 2c wert:

Stellen Sie sich vor, das Gedächtnis ist ein Haufen Kisten. Jede Box hat eine Nummer auf der Seite (die Adresse). Jede Box enthält eine Nummer (den Inhalt). Sie können mit diesen Boxen auf zwei Arten arbeiten: Variablen (ich möchte den Inhalt von Box N), Zeiger (ich möchte den Inhalt von Box, was auch immer in Box N ist ). Zeiger sind einfach Indirektion.

Und für die große Antwort, die alles abdeckt, was Sie jemals wissen müssen - lesen Sie dies .


++ So habe ich das Fach mehr oder weniger unterrichtet.
Mike Dunlavey

Überarbeiteter Artikel zur Unterstützung der OP-Anforderungen.
Gary Rowe

Welches Handbuch haben Sie verwendet, um zusätzliche NUL-Zeichen am Ende Ihrer Zeichenfolgen hinzuzufügen?
Rob Gilliam

@raimesh Ein sehr alter (um 1991). Ich kann mich nicht erinnern was.
Gary Rowe

1991? Das ist nicht alt für ein Handbuch in C-Sprache - die erste Ausgabe von K & R wurde 1978 veröffentlicht! Ich war nur neugierig, dass es jemals ein Handbuch gab, das darauf hinwies, dass Sie \ 0 am Ende Ihrer String-Konstanten einfügen mussten. (Als Sie es noch einmal betrachteten, wollten Sie eigentlich \ n?)
Rob Gilliam

4

Hol ein paar kleine Holzklötze.

Fügen Sie Metallhaken an einem Ende und Metallösen am anderen Ende hinzu.

Sie können jetzt eine verknüpfte Liste mit Dingen erstellen, mit denen Sie spielen können.

Versuchen Sie es mit dieser physischen Stütze zu erklären. Ich wünschte mir oft, ich hätte dies getan, als ich den Erstsemester-Schülern Hinweise gab.

Der kleine Metallhaken ist der Zeiger, der Holzblock, auf den das Ding zeigte.

Ich DEFY irgendjemand, um es nicht zu bekommen, nachdem ich mit den Blöcken gespielt habe.


4

Ich habe mir das Leben leichter gemacht, als ich einfach alle Flusen entfernt und angefangen habe, den Zeiger als eine andere Variable zu behandeln, anstatt als eine magische Entität (vor langer Zeit in Klasse 11). Ich weiß nur drei Dinge:

  1. Zeiger ist eine Variable, die die Adresse einer anderen Variablen (oder nur einer beliebigen Adresse) speichert.
  2. * wird verwendet, um den Wert an dem Speicherort abzurufen, der in der Zeigervariable gespeichert ist.
  3. & operator gibt die Adresse eines Speicherorts an.

Der Rest ist syntaktischer Zucker und gesunder Menschenverstand. Schreiben Sie einfach einige einfache C-Programme (wie das Implementieren einer verknüpften Listenbibliothek), indem Sie Zeiger verwenden, um einen Überblick zu erhalten.


2
  1. Der Zeiger kann als Verallgemeinerung eines Index in ein Array betrachtet werden.
    • Bedenken Sie, dass ein großes Array in eine Reihe kleinerer, nicht überlappender Arrays variabler Größe zerlegt werden kann. Diese kleineren Arrays sind das, was wir normalerweise als Array betrachten. Der größere ist dann der gesamte Speicherplatz des Computers. Das Abschneiden kleinerer Arrays wird als Speicherzuweisung bezeichnet.
  2. Eine Menge von Strukturen, die durch einige Zeiger miteinander verbunden sind, kann als gerichteter Graph angesehen werden .
    • Jeder Eckpunkt ist eine Variable, die einen bestimmten Wert enthalten kann.
    • Einige Variablen sind Zeiger, und jeder Zeiger kann genau eine ausgehende Kante zu etwas anderem haben.
    • Variablen, die keine Zeiger sind, haben keine ausgehende Flanke. Sie können eine beliebige Anzahl an eingehenden Flanken haben.

2

Ich kann mich nicht ganz an die Umstände um meinen Zeiger-Aha-Moment erinnern, aber ich habe das Gedächtnis um mein Verständnis eines Arrays im C-Stil nachträglich erweitert. (dh arr[3]ist das gleiche wie *(arr+3))

Aus irgendeinem Grund finde ich es sehr hilfreich, Zeiger als Arrays anzusehen, wenn ich auf eine Zeigersituation stoße.


2

Grundsätzlich hat @Gary Rowe das richtige Modell vorgestellt. Speicher als eine Reihe von Feldern mit Adressen (Zahlen) darauf. Jedes Feld speichert einen Wert (Nummer).

Die Idee eines Zeigers besteht darin, den Wert in einem Feld als die Adresse eines anderen Feldes zu interpretieren. Dieser Wert wird verwendet, um auf ein bestimmtes Feld zu verweisen , weshalb er als Referenz bezeichnet wird . Die Dereferenzierung ist somit der Vorgang des Öffnens der Box, auf die verwiesen wird.

Wenn vist eine Variable (Box), dann die Anweisung

  • vBedeutet Wert von v, dh gib mir was in der Box ist
  • *vbedeutet dereferenzieren den Wert von v, dh gib mir was in der Box steht, auf die sich der Wert von beziehtv
  • &vbedeutet referenz v, dh gib mir die adresse auf box

Ich denke, es dient nicht dem Zweck, Zeiger als etwas völlig anderes einzuführen. Es war ein Konzept, das für mich als Kind schwer zu verstehen war. Es schien immer eine dunkle Magie zu sein, die ich nie wirklich verstanden habe und die viele Sonderzeichen brauchte. Das erste Mal, dass ich es verstanden habe, war, als ich ein kleines Spiel mit doppelter Indirektion in einer Sprache schrieb, die keine Zeigerarithmetik hat. Das hat mich aufgeklärt.

Hinweise sind eine Frage der Interpretation. Ich denke, das zu erklären macht die Sache viel einfacher. Und Zeigerarithmetik ist eine äußerst einfache und intuitive Operation, wenn ein einfaches Beispiel mit einem Speicher von 10 Variablen gezeigt wird.


2

Die Erklärung, die ich wirklich grocked war:

Stellen Sie sich ein Stadtgitter mit verschiedenen Häusern auf Grundstücken vor. In deiner Hand hältst du ein Stück Papier. Auf dem Papier, das Sie geschrieben haben:


Davids Haus,

112 So und so Straße.


Das Blatt Papier (Zeigervariable) enthält eine Adresse, die auf Davids Haus verweist . Wenn Sie einem Freund sagen möchten, dass er sich Davids cooles Haus ansehen soll, ist es viel einfacher, das Stück Papier als Referenz für das Haus zu verwenden, als das eigentliche zweistöckige Gebäude per Post zu verschicken.

Wie bei echten Zeigern kann es zu Problemen kommen, wenn Sie der Adresse auf Ihrem Blatt Papier folgen. David hätte umziehen können und wenn du dort ankommst, findest du nur ein großes Loch im Boden. In diesem Fall wäre es besser gewesen, die Adresse auf dem Papier zu löschen, wenn David umgezogen wäre, oder sie zumindest in die neue Adresse zu ändern. Sie könnten auch feststellen, dass Sie zur Adresse gehen und das Wohnzimmer Ihres Freundes David betreten, aber dieses Mal landen Sie in einem völlig fremden Schwimmbad. Jemand anderes hat den Platz an der Adresse, die Sie hatten, für etwas völlig anderes verwendet.


2

Wenn Sie Zeiger erklären möchten, müssen Sie zuerst das Gedächtnis erklären. Ich mache das normalerweise mit Millimeterpapier / Karopapier mit Zeilen und Spalten. Wenn die "Studentin" das Gedächtnis versteht, kann sie verstehen, was eine Adresse ist. Wenn Sie Adresse haben, haben Sie Zeiger.

Sie können mit dieser Abstraktion spielen. ZB schreiben Sie die Adresse (Nummer) eines Quadrats in ein anderes Quadrat. Zeichnen Sie nun einen Pfeil vom Zeigerfeld zum Zielfeld. Überschreiben Sie nun den Zeiger (z. B. inkrementieren Sie ihn) und passen Sie den Pfeil an. Schreiben Sie eine Adresse in ein anderes Feld und lassen Sie den Schüler den Pfeil zeichnen ...

Nächster Schritt: Geben Sie bestimmten Quadraten (wie dem Zeiger) einen Namen. Jetzt können Sie die Dereferenzierung erklären. Das ist es.


2
Erinnert mich an einen "Computer", den ich verwendet habe, bevor ich einen in die Hände bekommen konnte, der tatsächlich Elektronen verwendete - den Karton "CARDIAC", wie ich glaube, er hieß. Buchstäblich Zahlen in nummerierte Felder schreiben, um Zahlen aus anderen nummerierten Feldern zu erhalten. Es war lehrreich und ich hatte nie Probleme, Hinweise auf echte Mikroprozessoren zu verstehen.
DarenW

2

Vielleicht bin es nur ich, aber ich arbeite gut mit Analogien. Nehmen wir also an, Sie haben einen Freund (Funktion / Klasse) "Foo", der möchte, dass sich jemand anderes (andere Funktion / Klasse), "Bar", mit Ihnen aus irgendeinem Grund in Verbindung setzt. "Foo" könnte dich dazu bringen, "Bar" zu besuchen, aber das ist nicht bequem, all diese Wesen (Instanzen) herumzubewegen. Allerdings könnte "Foo" "Bar" Ihre Telefonnummer (Zeiger) senden. So weiß "Foo", egal wo Sie sich befinden, wie Sie sich mit Ihnen in Verbindung setzen können, ohne Sie finden zu müssen.

Angenommen, "Bar" hat einen Bekannten, "Baz", der sich ebenfalls mit Ihnen in Verbindung setzen möchte. Aber Sie schützen Ihre Telefonnummer und möchten nicht, dass alle diese haben. "Baz" kann "Bar" (Telefon als Zeiger) anrufen, der den Anruf dann an Sie weiterleiten kann (ein anderer Zeiger). Und so weiter und so fort in der Kette der Freunde und Freunde von "Baz".


2

Pointers macht Weg mehr Sinn , wenn Sie Assembler - Sprache und / oder Computerarchitektur studiert haben. Ich denke, wenn ich eine C-Klasse unterrichte, würde ich mit ein paar Wochen Architektur beginnen, um das Speichermodell und die Arten von Anweisungen zu erklären, die der Prozessor tatsächlich ausführt.


Absolut. Wenn Sie sich mit Registern befassen und Dinge wie unmittelbare Werte und indirekte Adressierung verstehen, ist das gesamte Konzept der Zeiger intuitiv. Ich lernte 6502-Assembly und dann 68K-Assembly, bevor ich meine erste Zeile von C schrieb. Als ich mit den Zeigern bekannt wurde, schaute ich mir die (Zwischen-) Assembly des Compilers an und sie war genau wie erwartet.
Radian

2

Mein "aha!" Moment kam in diesem Tutorial:

Ein Tutorial zu Zeigern und Arrays in C

Um genau zu sein, kam es in diesem Kapitel: Kapitel 3: Zeiger und Strings

Genauer gesagt kam es mit diesem Satz:

Der an puts () übergebene Parameter ist ein Zeiger, dh der Wert eines Zeigers (da alle Parameter in C als Wert übergeben werden), und der Wert eines Zeigers ist die Adresse, auf die er verweist, oder einfach eine Adresse .

Als ich das las, teilten sich die Wolken und Engel bliesen Trompetenfanfaren.

Wie Sie sehen, hatte jedes C-Tutorial oder Buch, das ich zuvor gelesen hatte, behauptet, dass C nach Wert oder Referenz eine schändliche Lüge sein könnte. Die Wahrheit ist, dass C immer als Wert übergeben wird, aber manchmal handelt es sich bei dem übergebenen Wert zufällig um eine Adresse. Innerhalb der Methode wird eine Kopie dieser Adresse erstellt, genau wie eine Kopie eines übergebenen Int. Eine Kopie des Werts, auf den der Zeiger zeigt, wird nicht erstellt. Mit dem Zeiger innerhalb der Methode können Sie also auf den ursprünglichen Wert zugreifen und diesen ändern.

Ich wurde nie ein C-Programmierer, aber ich wurde ein .NET-Programmierer, und Objekte und Objektreferenzen funktionieren auf die gleiche Weise. Der Verweis auf das Objekt wird als Wert übergeben (und somit kopiert), das Objekt selbst wird jedoch nicht kopiert. Ich habe mit vielen Programmierern gearbeitet, die das nicht verstehen, weil sie nie Zeiger gelernt haben.


1

Der Trick besteht darin, zu erklären, dass der Ort eines Objekts und das Objekt selbst nicht gleich sind, genau wie ein Bild einer Pfeife keine Pfeife ist . Wenn Sie ein Objekt verschieben, ändert sich seine Position. Der Ort bleibt und etwas anderes kann dort gestellt werden.


1

Ein Zeiger ist eine Notiz, die Ihnen sagt, wo etwas Nützliches ist. Es enthält die Position des Objekts und gibt an, wie groß das Objekt ist (jedenfalls in C). Ein Doppelzeiger ist also wie eine Haftnotiz mit der Aufschrift "Im Kühlschrank ist ein Sechserpack". Um herauszufinden, ob es sich um Cola oder Budweiser handelt, muss man das Sixpack holen.


1

Angesichts des Codes:

int v=42; // Deklarieren und Initialisieren einer einfachen Variablen

int *p = &v; // Erzeugen eines Punktes p auf die Variable v

Über den obigen Code kann folgendes gesagt werden:

int * p // "int pointer p" ... so deklarieren Sie einen Zeiger auf eine Variable vom Typ int

*p // "wies auf p" ... das sind die Daten, auf die p zeigt, dasselbe wie v.

&v // "Adresse der Variablen v" ... das ist der Literalwert für p


1

http://cslibrary.stanford.edu/

Diese Site bietet großartige Tutorials für Lernhinweise und Speicherverwaltung.

Ich würde vorschlagen, dass Sie die Grundlagen, die Zeiger und den Speicher, die auf der Site angegeben sind, durchgehen. Sie können sich auch die Probleme mit verknüpften Listen ansehen, die auf dem Link angegeben sind, um die Zeigerkonzepte weiter zu stärken.


1

Der Schlüssel zum Erklären von Zeigern besteht darin, sicherzustellen, dass die Personen, denen Sie erklären, das Konzept des Gedächtnisses bereits verstehen. Es wäre zwar schön, wenn sie es auf niedriger Ebene wirklich verstanden hätten, aber es reicht aus, zu glauben, dass Speicher als massives Array vorhanden ist, und zu verstehen, dass Sie über seine Indexposition auf jede Position im Array zugreifen können.

Der nächste Schritt besteht für die meisten Menschen darin, den Indexstandort zu übergeben, anstatt den gesamten Speicher zu kopieren. Und das reicht aus, damit die meisten Menschen verstehen, warum Zeiger nützlich sind.

Der letzte Schritt zum Verstehen von Zeigern besteht darin, zu erklären, wie Sie als Parameter einen Speicherindexort für die Methode übergeben können, um den Indexort zu speichern, an dem alle Daten gespeichert sind. Ich habe festgestellt, dass dies für manche Menschen zu weit gehen kann.

Sobald jemand diese grundlegenden Schritte verstanden hat, kann er sofort feststellen, dass Sie Zeiger auf unbestimmte Zeit verketten können, solange Sie nachverfolgen, wie oft Sie nach Adressen suchen müssen, um das eigentliche Datenobjekt zu finden.

Sobald jemand Zeiger erfasst hat, muss er als Nächstes schnell den Unterschied zwischen Heapspeicher und Stapelspeicher erkennen und herausfinden, warum Zeiger zum Stapeln von Speicher gefährlich sind, wenn sie außerhalb der Methode übergeben werden.


0

Ich erinnere mich an ein Buch "C-Rätsel" oder ähnliches, das ich nur las, weil es eines der wenigen programmier- / computerbezogenen Bücher in der Bibliothek war. Mein Verständnis von C war rudimentär. Es warf eine C-Expresison auf Sie und bat Sie, sie zu untersuchen, was immer komplizierter wurde.


0

Als ich an der Universität war, hatte mein Professor einige wirklich nette Powerpoint-Folien, auf denen ein Punkt als separate Variable mit einem Pfeil zu einem Speicherort (dargestellt wie ein Array) dargestellt war, und als wir verknüpfte Listen machten, tat er es Schritt für Schritt - Schritt für Schritt: Zeigt an, wann sich der Pfeil ändert, wann der Zeiger dereferenziert wird usw. - Es gab keine Möglichkeit, dass man es innerhalb weniger Minuten nicht verstehen konnte. Das Konzept selbst ist sehr einfach, aber es richtig zu machen oder es in praktischen Programmen anzuwenden, erfordert mehr Übung.


0

Bevor ich das tue, erkläre ich, dass bei der Programmierung "alles Speicher verwendet" und (statische) Variablenzuweisung im Speicher. Ich werde auch erklären, was eine Speicheradresse ist, und die Beziehung zwischen Speicherplatz, Speicheradresse und Variablen.

Schließlich erkläre ich, dass es Integer-Datentypen und -Variablen, String-Datentypen und -Variablen usw. gibt, bis ich erkläre, dass es einen speziellen Datentyp gibt, der Speicheradressen speichert und einen leeren Wert wie "0" hat. genannt null .

Und schließlich dynamisch zugewiesene Variablen durch die Verwendung von Zeigern.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.