Nun, ich verstehe im Grunde, wie man Zeiger benutzt, aber nicht, wie man sie am besten benutzt, um besser zu programmieren.
Was sind gute Projekte oder Probleme, die mit der Verwendung von Zeigern gelöst werden müssen, damit ich sie besser verstehen kann?
learning
c++
personal-projects
pointers
Dysoko
quelle
quelle
Antworten:
Wenn Sie große Datenmengen im Speicher bearbeiten, leuchten die Zeiger wirklich.
Das Übergeben eines großen Objekts als Referenz entspricht dem Übergeben einer einfachen alten Zahl. Sie können die benötigten Teile direkt bearbeiten, anstatt ein Objekt zu kopieren, zu ändern und dann die Kopie an die Stelle des Originals zurückzugeben.
quelle
Mit dem Zeigerkonzept können Sie nach Adresse auf Daten verweisen, ohne die Speicherung von Daten zu duplizieren. Dieser Ansatz ermöglicht das Schreiben effizienter Algorithmen wie:
Sortieren
Wenn Sie Daten in einem Sortieralgorithmus verschieben, können Sie den Zeiger anstelle der Daten selbst verschieben. Sie können beispielsweise Millionen von Zeilen in einer Zeichenfolge von 100 Zeichen sortieren. Sie sparen eine Menge unnötiger Datenbewegungen.
Verknüpfte Listen
Sie können den nächsten und / oder vorherigen Elementspeicherort und nicht die gesamten mit dem Datensatz verknüpften Daten speichern.
Übergeben von Parametern
In diesem Fall übergeben Sie die Adresse der Daten anstelle der Daten selbst. Stellen Sie sich erneut einen Algorithmus zur Namenskomprimierung vor, der in Millionen von Zeilen ausgeführt wird.
Das Konzept kann auf Datenstrukturen wie relationale Datenbanken erweitert werden, bei denen ein Zeiger einem Fremdschlüssel ähnelt . In einigen Sprachen wird die Verwendung von Zeigern wie C # und COBOL nicht empfohlen.
Beispiele finden Sie an vielen Stellen wie:
Der folgende Beitrag kann in gewisser Weise relevant sein:
quelle
Ich bin überrascht, dass keine andere Antwort dies erwähnt hat: Mit Zeigern können Sie nicht zusammenhängende und nicht lineare Datenstrukturen erstellen, bei denen ein Element auf komplexe Weise mit mehreren anderen verknüpft sein kann.
Verknüpfte Listen (einfach, doppelt und zirkulär verknüpft), Bäume (rot-schwarz, AVL, trie, binär, Raumaufteilung…) und Diagramme sind Beispiele für Strukturen, die am natürlichsten in Bezug auf Verweise und nicht nur auf Werte konstruiert werden können .
quelle
Ein einfacher Weg ist der Polymorphismus. Polymorphismus funktioniert nur mit Zeigern.
Außerdem verwenden Sie Zeiger immer dann, wenn Sie eine dynamische Speicherzuweisung benötigen. In C geschieht dies normalerweise, wenn Sie Daten in einem Array speichern müssen, aber die Größe zum Zeitpunkt der Kompilierung nicht kennen. Sie würden dann malloc aufrufen, um den Speicher zuzuweisen, und einen Zeiger, um darauf zuzugreifen. Unabhängig davon, ob Sie es wissen oder nicht, verwenden Sie Zeiger, wenn Sie ein Array verwenden.
ist das Äquivalent von
Mit diesem Wissen können Sie wirklich coole Dinge tun, wie das Kopieren eines gesamten Arrays in einer Zeile:
In c ++ verwenden Sie new, um einem Objekt Speicher zuzuweisen und in einem Zeiger zu speichern. Sie tun dies immer dann, wenn Sie ein Objekt zur Laufzeit anstatt zur Kompilierungszeit erstellen müssen (dh eine Methode erstellt ein neues Objekt und speichert es in einer Liste).
Zeiger besser verstehen:
Suchen Sie nach Projekten, die Vererbung verwenden.
Hier ist das Projekt, an dem ich meine Zähne geschnitten habe:
Lesen Sie zwei nxn-Matrizen aus einer Datei ein, führen Sie die grundlegenden Vektorraumoperationen aus und drucken Sie das Ergebnis auf dem Bildschirm aus.
Dazu müssen Sie dynamische Arrays verwenden und durch Zeiger auf Ihre Arrays verweisen, da Sie zwei Arrays von Arrays haben (mehrdimensionale dynamische Arrays). Nachdem Sie das Projekt abgeschlossen haben, haben Sie eine ziemlich gute Idee, wie Sie Zeiger verwenden.
quelle
Um wirklich zu verstehen, warum Zeiger wichtig sind, müssen Sie den Unterschied zwischen der Heap-Zuweisung und der Stapelzuweisung verstehen.
Das Folgende ist ein Beispiel für eine Stapelzuweisung:
Auf dem Stack zugewiesene Objekte existieren nur für die Dauer der aktuellen Funktionsausführung. Wenn der Aufruf
foo
von den Gültigkeitsbereich verlässt, verlässt auch die Variable den Gültigkeitsbereichf
.Ein Fall, bei dem dies zu einem Problem wird, besteht darin, dass Sie von einer Funktion etwas anderes als einen ganzzahligen Typ zurückgeben müssen (z. B. die Foo-Struktur aus dem obigen Beispiel).
Beispielsweise würde die folgende Funktion zu einem sogenannten "undefinierten Verhalten" führen.
Wenn Sie so etwas wie
struct Foo *
von einer Funktion zurückgeben möchten, brauchen Sie wirklich eine Heap-Zuordnung:Die Funktion
malloc
weist ein Objekt auf dem Heap zu und gibt einen Zeiger auf dieses Objekt zurück. Es ist zu beachten, dass der Begriff "Objekt" hier lose verwendet wird und "etwas" anstelle von Objekt im Sinne einer objektorientierten Programmierung bedeutet.Die Lebensdauer von Heap-zugewiesenen Objekten wird vom Programmierer gesteuert. Der Speicher für dieses Objekt wird reserviert, bis der Programmierer ihn freigibt, dh durch Aufrufen
free()
oder bis das Programm beendet wird.Bearbeiten : Ich habe nicht bemerkt, dass diese Frage als C ++ - Frage markiert ist. Die C ++ - Operatoren
new
undnew[]
führen die gleiche Funktion aus wiemalloc
. Die Operatorendelete
unddelete[]
sind analog zufree
. Währendnew
unddelete
ausschließlich zum Zuweisen und Freigeben von C ++ - Objekten verwendet werden sollte, ist die Verwendung vonmalloc
undfree
im C ++ - Code vollkommen legal.quelle
Schreiben Sie ein nicht-triviales Projekt in C und Sie werden herausfinden müssen, wie / wann Sie Zeiger verwenden sollen. In C ++ werden Sie meist RAII-fähige Objekte verwenden, die Zeiger intern verwalten, in C-Raw-Zeigern jedoch eine weitaus häufigere Rolle spielen. Was für ein Projekt Sie tun sollten, es kann alles sein, was nicht trivial ist:
Ich empfehle den letzten.
quelle
Fast alle Programmierprobleme, die mit Zeigern gelöst werden können, können mit anderen sichereren Referenztypen gelöst werden (nicht mit Bezug auf C ++ - Referenzen , aber das allgemeine CS-Konzept, eine Variable zu haben, bezieht sich auf den Wert von Daten, die an anderer Stelle gespeichert sind).
Zeiger, bei denen es sich um eine spezielle Implementierung von Verweisen auf niedriger Ebene handelt, bei denen Sie Speicheradressen direkt bearbeiten können, sind sehr leistungsfähig, können jedoch in der Verwendung etwas gefährlich sein (z. B. auf Speicherorte außerhalb des Programms verweisen).
Die direkte Verwendung von Zeigern hat den Vorteil, dass sie etwas schneller sind, da keine Sicherheitsprüfungen durchgeführt werden müssen. Sprachen wie Java, die Zeiger im C-Stil nicht direkt implementieren, leiden unter leichten Leistungseinbußen, reduzieren jedoch viele Arten von schwierig zu debuggenden Situationen.
Was den Grund für die Notwendigkeit einer Indirektion angeht, ist die Liste ziemlich lang, doch im Wesentlichen lauten die beiden Schlüsselideen:
selected_object
, die auf eines der Objekte verweist, ist wesentlich effizienter als das Kopieren des Werts des aktuellen Objekts in eine neue Variable.quelle
Die Bildbearbeitung auf Pixelebene ist mit Zeigern fast immer einfacher und schneller. Manchmal ist es nur mit Zeigern möglich.
quelle
Zeiger werden in so vielen Programmiersprachen unter der Oberfläche verwendet, ohne den Benutzer darüber zu ärgern. Mit C / C ++ haben Sie nur Zugriff darauf.
Verwendung: So oft wie möglich, da das Kopieren von Daten ineffizient ist. Wann Sie sie nicht verwenden sollen: Wenn Sie zwei Kopien möchten, die einzeln geändert werden können. (Was im Grunde dazu führt, dass der Inhalt von object_1 an eine andere Stelle im Speicher kopiert und ein Zeiger zurückgegeben wird - diesmal auf object_2)
quelle
Zeiger sind ein wesentlicher Bestandteil jeder Datenstrukturimplementierung in C, und Datenstrukturen sind ein wesentlicher Bestandteil jedes nicht trivialen Programms.
Wenn Sie erfahren möchten, warum Zeiger so wichtig sind, sollten Sie lernen, was eine verknüpfte Liste ist, und versuchen, eine Liste zu schreiben, ohne Zeiger zu verwenden. Ich habe Ihnen keine unmögliche Herausforderung gestellt. (TIPP: Mit Zeigern wird auf Speicherstellen im Speicher verwiesen. Wie verweisen Sie auf Elemente in Arrays?)
quelle
Beispiel aus der Praxis: Erstellen eines Limit-Orderbuchs.
Der ITCH 4.1-Feed hat beispielsweise das Konzept, Aufträge zu ersetzen, bei denen sich die Preise (und damit die Priorität) ändern können. Sie möchten Aufträge entgegennehmen und an einen anderen Ort verschieben können. Das Implementieren einer Warteschlange mit zwei Enden und Zeigern macht die Operation sehr einfach.
quelle
Beim Durchsuchen der verschiedenen StackExchange-Sites stelle ich fest, dass es ziemlich angesagt ist, eine solche Frage zu stellen. Mit der Gefahr von Kritik und Abstimmungen bin ich ehrlich. Das soll nicht trollen oder flammen, ich will nur helfen, indem ich eine ehrliche Einschätzung der Frage gebe.
Und diese Einschätzung lautet wie folgt: Dies ist eine sehr seltsame Frage, die sich ein C-Programmierer stellen muss. Ziemlich alles, was es sagt, ist "Ich weiß nicht, C." Wenn ich ein bisschen weiter und zynischer analysiere, gibt es einen Grund für die Beantwortung dieser "Frage": "Gibt es eine Abkürzung, die ich verwenden kann, um schnell und plötzlich das Wissen eines erfahrenen C-Programmierers zu erlangen, ohne Zeit darauf zu verwenden? für ein unabhängiges Studium? " Jede "Antwort", die jemand geben kann, ist kein Ersatz dafür, das zugrunde liegende Konzept und seine Verwendung zu verstehen.
Ich finde es konstruktiver, C aus erster Hand zu lernen, als im Internet zu surfen und die Leute danach zu fragen. Wenn Sie C gut kennen, werden Sie sich nicht die Mühe machen, Fragen wie diese zu stellen, sondern fragen: "Welche Probleme lassen sich am besten mit einer Zahnbürste lösen?"
quelle
Auch wenn Zeiger bei der Arbeit mit großen Speicherobjekten wirklich strahlen, gibt es immer noch eine Möglichkeit, dies auch ohne sie zu tun.
Die Zeiger sind für die sogenannte dynamische Programmierung unbedingt erforderlich, wenn Sie nicht wissen, wie viel Speicher Sie benötigen, bevor Ihr Programm ausgeführt wird. Bei der dynamischen Programmierung können Sie zur Laufzeit Speicherabschnitte anfordern und Ihre eigenen Daten in diese einfügen. Sie benötigen also Zeiger oder Referenzen (der Unterschied ist hier nicht wichtig), um mit diesen Datenabschnitten arbeiten zu können.
Solange Sie zur Laufzeit einen bestimmten Speicher beanspruchen und Ihre Daten in den neu erfassten Speicher stellen können, können Sie Folgendes tun:
Sie können sich selbst erweiternde Datenstrukturen haben. Dies sind Strukturen, die sich erweitern können, indem sie zusätzlichen Speicher beanspruchen, solange ihre Kapazität erschöpft ist. Die Schlüsseleigenschaft jeder sich selbst erweiternden Struktur besteht darin, dass sie aus kleinen Speicherblöcken (je nach Struktur als Knoten, Listenelemente usw. bezeichnet) besteht und jeder Block Verweise auf andere Blöcke enthält. Diese "verknüpften" Strukturen bilden die Mehrzahl der modernen Datentypen: Diagramme, Bäume, Listen usw.
Sie können mit dem OOP-Paradigma (Object-Oriented Programming) programmieren. Die gesamte OOP basiert auf der Verwendung nicht direkter Variablen, sondern auf Verweisen auf Klasseninstanzen (als Objekte bezeichnet) und deren Manipulation. Keine einzelne Instanz kann ohne Zeiger existieren (auch wenn es möglich ist, nur statische Klassen ohne Zeiger zu verwenden, ist dies eher eine Ausnahme).
quelle
Witzig, ich habe gerade eine Frage zu C ++ beantwortet und über Zeiger gesprochen.
In der Kurzversion benötigen Sie NIEMALS Zeiger, es sei denn, 1) die Bibliothek, die Sie verwenden, erzwingt Sie. 2) Sie benötigen eine nullfähige Referenz.
Wenn Sie ein Array, eine Liste, eine Zeichenfolge usw. benötigen, müssen Sie es nur auf dem Stapel haben und ein stl-Objekt verwenden. Das Zurückgeben oder Übergeben von STL-Objekten ist schnell (ungeprüfte Tatsache), da sie internen Code haben, der einen Zeiger anstelle eines Objekts kopiert und die Daten nur dann kopiert, wenn Sie darauf schreiben. Dies ist normales C ++, nicht einmal das neue C ++ 11, das es Bibliotheksschreibern leichter machen wird.
Ihre Frage könnte an dieser Stelle beantwortet werden
Wenn Sie einen Zeiger verwenden, stellen Sie sicher, dass er sich in einer dieser beiden Bedingungen befindet. 1) Sie übergeben eine Eingabe, die möglicherweise nullwertfähig ist. Ein Beispiel ist ein optionaler Dateiname. 2) Wenn Sie Eigentum verschenken möchten. Als ob Sie den Zeiger übergeben oder zurückgeben, haben Sie KEINE Kopien davon übrig, noch verwenden Sie den Zeiger, den Sie verschenken
Aber ich habe seit langer Zeit keine Zeiger oder intelligenten Zeiger mehr verwendet und meine Anwendung profiliert. Es läuft sehr schnell.
ZUSÄTZLICHER HINWEIS: Ich stelle fest, dass ich meine eigenen Strukturen schreibe und sie weitergebe. Wie mache ich das, ohne Zeiger zu verwenden? Es ist kein STL-Container, daher ist das Vorbeifahren an ref langsam. Ich lade immer meine Datenliste / deques / maps und so. Ich kann mich nicht erinnern, Gegenstände zurückgegeben zu haben, es sei denn, es handelte sich um eine Liste / Karte. Nicht einmal eine Schnur. Ich habe mir den Code für einzelne Objekte angesehen und dabei
{ MyStruct v; func(v, someinput); ... } void func(MyStruct&v, const D&someinput) { fillV; }
festgestellt, dass ich so etwas mache, dass ich so ziemlich alle Objekte zurückgebe (mehrere) oder eine Referenz vorbelege / übergebe, um sie zu füllen (einzelne).Wenn Sie nun schreiben, dass Sie eine eigene Deque, Map usw. sind, müssen Sie Zeiger verwenden. Das musst du aber nicht. Lassen Sie STL und möglicherweise steigern Sie die Sorge darüber. Sie müssen nur Daten und die Lösungen schreiben. Keine Container, um sie aufzunehmen;)
Ich hoffe, Sie verwenden jetzt niemals Zeiger: D. Viel Glück beim Umgang mit Bibliotheken, die Sie dazu zwingen
quelle
Zeiger sind sehr nützlich für die Arbeit mit Geräten mit Speicherzuordnung. Sie können eine Struktur definieren, die beispielsweise ein Steuerregister widerspiegelt, und diese dann der Adresse des tatsächlichen Steuerregisters im Speicher zuweisen und direkt bearbeiten. Sie können auch direkt auf einen Übertragungspuffer auf einer Karte oder einem Chip zeigen, wenn die MMU ihn dem Systemspeicher zugeordnet hat.
quelle
Ich sehe Zeiger als Zeigefinger, mit denen wir einige Dinge tun:
Bitte vergib diese schlechte Antwort
quelle
Da Ihre Frage mit C ++ markiert ist, beantworte ich Ihre Frage für diese Sprache.
In C ++ wird zwischen Zeigern und Referenzen unterschieden. Daher gibt es zwei Szenarien, in denen Zeiger (oder intelligente Zeiger) erforderlich sind, um bestimmte Verhaltensweisen zu vereinfachen. Sie können unter anderen Umständen verwendet werden, Sie fragen jedoch, wie Sie sie am besten verwenden können, und unter allen anderen Umständen gibt es bessere Alternativen.
1. Polymorphismus
Mit einem Basisklassenzeiger können Sie eine virtuelle Methode aufrufen, die vom Typ des Objekts abhängt, auf das der Zeiger zeigt.
2. Persistente Objekte erstellen
Zeiger sind erforderlich, wenn ein Objekt dynamisch erstellt wird (auf dem Heap anstelle des Stapels). Dies ist erforderlich, wenn die Lebensdauer von Objekten länger sein soll als der Bereich, in dem sie erstellt werden.
In Bezug auf "gute Projekte oder zu lösende Probleme", wie andere bereits gesagt haben, wird jedes nicht-triviale Projekt Zeiger verwenden.
quelle