Was sind Anwendungsfälle und Vorteile von Zeigern? [geschlossen]

10

Ich habe oft Schwierigkeiten, die Vorteile von Zeigern zu erkennen (außer bei der Programmierung auf niedriger Ebene).

Warum char * anstelle eines Strings oder char [] verwenden oder welche Vorteile Zeigerarithmetik bringt.

Was sind die Profis und Anwendungsfälle von Zeigern?

OliverS
quelle
6
Das wird ein bisschen elitär klingen, aber IMHO, wenn Sie nach Vor- und Nachteilen von Zeigern fragen müssen, brauchen Sie sie höchstwahrscheinlich nicht.
Jas
3
Wahrscheinlich! Aber die Frage ist immer noch gültig!
Zolomon
1
Dies ist auch nicht wirklich sprachunabhängig, da nicht alle Programmiersprachen echte Zeiger im C-Sinne haben.
David Thornley

Antworten:

6

Zeiger sind für den dynamischen Speicherort, viele Datenstrukturen und den effizienten Umgang mit großen Datenmengen erforderlich. Ohne Zeiger müssten Sie alle Programmdaten global oder in Funktionen oder dergleichen zuordnen, und Sie hätten keinen Rückgriff, wenn die Datenmenge über das hinausgehen würde, was Sie ursprünglich zugelassen hatten. Ich zögere, hier Absolutes zu verwenden, aber soweit ich weiß, haben alle modernen Computersprachen Zeiger in irgendeiner Form.

In den meisten Sprachen, die Zeiger verwenden, gibt es bestimmte Arten von Referenzen, die Zeiger sind, und möglicherweise bestimmte Arten von Referenzen, die dies nicht sind, und es gibt keinen weiteren Unterschied in der Notation. Eine Lisp- consZelle ist ein Zeigerpaar, obwohl a fixnumkein Zeiger ist. In Java ist die für die Instanz einer Klasse verwendete Variable ein Zeiger, ein Zeiger jedoch intnicht. Die Sprachsyntax spiegelt dies nicht wider.

C ist insofern ungewöhnlich, als Zeiger optional und explizit sind und eine explizite Zeigerarithmetik zulassen. Es ist durchaus möglich , zu schreiben struct foo bar; struct foo * baz;, und wenn Sie Speicher zugewiesen haben für bazSie beide zu verwenden barund bazdarzustellen struct foos. Da Zeiger optional sind, ist es nützlich, Unterschiede in der Notation zu haben. (In C ++ ist es wichtig, dass intelligente Zeiger, wie angegeben boost::shared_ptr<foo> bar;, bar.reset()eine Bedeutung haben und bar->reset()wahrscheinlich eine ganz andere haben.)

(Tatsächlich wurden explizite Zeiger häufig in anderen Sprachen verwendet, als C ursprünglich entwickelt wurde, wie beispielsweise ^in Pascal. C ist eine ältere Sprache als die meisten heute gebräuchlichen und zeigt dies.)

Eines der Entwurfsziele von C war das Schreiben von Unix. Daher musste der Speicherort detailliert behandelt werden. (C gehört tatsächlich zu einer Familie von Systemimplementierungssprachen, die bei der Entwicklung häufig verwendet wurden. Ein weiteres Beispiel ist Cybol für Control Data-Computer. C ist ein großer Erfolg.) Daher ist es möglich, C-Zeiger direkt zu manipulieren. Speicheradressen zuweisen und neue berechnen. Dies führte auch zu einigen Entwurfsentscheidungen in C. C-Arrays basieren stark auf Zeigerarithmetik, und tatsächlich zerfällt ein Array in sehr vielen Situationen in einen Zeiger. Die Übergabe von Variablen an C-Funktionen als Referenz erfolgt per Zeiger. Es bestand kein starker Bedarf an Arrays und Übergabe von Variablen als Referenz in der Form, die andere zeitgenössische Sprachen hatten, so dass C diese nicht bekam.

Die Antwort lautet also, dass Sie heutzutage in den meisten Sprachen ständig Zeiger verwenden, ohne daran erinnert zu werden. In C und in geringerem Maße in C ++ verwenden Sie Zeiger entweder, um Dinge auf niedriger Ebene auszuführen oder um Dinge auf höherer Ebene auszuführen, für die es keine spezielle Notation gibt.

David Thornley
quelle
sehr schöne Antwort
Kate Gregory
1
Ich akzeptiere diese Antwort, weil sie am besten den Unterschied beschreibt, den ich zwischen Zeigern in C / C ++ und Referenz in Java nicht erfassen konnte.
OliverS
Es wäre gut, eine kurze Erklärung hinzuzufügen, warum Java keine Zeiger verwendet, um den von Gosling (Javas Hauptschöpfer) wahrgenommenen "Betrug" besser zu verdeutlichen.
Guido Anselmi
10

Komplexe Datenstrukturen. Sie können so etwas wie eine verknüpfte Liste oder einen Binärbaum nicht ohne Zeiger erstellen.

Es gibt keine "Vor- und Nachteile" von Zeigern. Sie sind nur ein Werkzeug wie ein Hammer.

zvrba
quelle
5
In Java gibt es keine Zeiger. Es ist jedoch möglich, eine verknüpfte Liste und einen Binärbaum zu erstellen. Es gibt einen Unterschied zwischen Referenzen (wie in Java) und Zeigern (wie in C).
StartClass0830
7
Es gibt keinen Unterschied zwischen Referenzen und Zeigern. Die Zeigerarithmetik ist C-spezifisch; Es gibt andere Sprachen, die Zeiger haben, aber keine Zeigerarithmetik (z. B. Pascal).
Zvrba
1
Zeiger und Referenzen sind nicht gleichbedeutend mit Ihrer Meinung. Lesen Sie dies, um die Unterschiede zu sehen. stackoverflow.com/questions/57483/…
StartClass0830
4
So adressieren Sie die ersten beiden Elemente dieser Liste: Java-Referenzen können neu zugewiesen werden und auf Null zeigen. Das Unterscheidungsmerkmal eines Zeigers besteht darin, dass Sie indirekt auf ein anderes Objekt verweisen können. Mein Lackmustest lautet: Wenn Sie eine zirkuläre Datenstruktur erstellen können (die Sie mit Java-Referenzen erstellen können), ist dies ein Zeiger. (Beachten Sie, dass Sie keine kreisförmige Datenstruktur mit C ++ - Referenzen
erstellen können
1
Es gibt einen Unterschied zwischen Zeigern und Referenzen. C # hat zum Beispiel beides . ( blogs.msdn.com/b/ericlippert/archive/2009/02/17/… )
Steven Evers
2
  • Mit Zeigern können Sie Speicher zur Laufzeit zuweisen und freigeben.
  • Und Sie können große Datenstrukturen außerhalb des zulässigen Bereichs verwenden, ohne kopiert zu werden.

Referenzen in C ++, Java und anderen Sprachen sind nur "sichere Zeiger". Und diese Referenzen werden in Java häufig verwendet.

Gulshan
quelle
1
Referenzen in C ++ sind KEINE sicheren Zeiger. Referenzen in C ++ haben überhaupt nichts mit Zeigern zu tun. Referenzen in C ++ sind Aliase . Sie können nicht zugewiesen NULLund nach ihrer Erstellung nicht mehr geändert werden.
Billy ONeal
@Billy: C ++ - Referenzen werden normalerweise mithilfe von Zeigern implementiert und funktionieren in einigen Dingen ähnlich, sodass die Leute sie immer wieder als eine Art eingeschränkten Zeiger betrachten.
David Thornley
2

So ziemlich jedes Computerprogramm muss Werte im Speicher überprüfen und ändern (bekannt als Spähen und Stöbern für diejenigen von uns, die alt genug sind). Sie müssen steuern, wo sich diese Werte im Speicher befinden, damit das Ergebnis vorhersehbar ist (und in bestimmten Fällen ist die Reihenfolge wichtig: Das Laden von ausführbarem Code ist ein Beispiel). Daher benötigen Sie einen Datentyp, der einen Speicherort im Speicher darstellt. Auch wenn Ihre Programmierumgebung dies unter einer Abstraktion verbirgt, ist es immer noch da.


quelle
2

char*ist ein mieses Beispiel für Zeiger. Sie sind wahrscheinlich besser dran als std::string(oder ein besserer Typ, der Ihre Unicode / Ansi / Multibyte-Spezialität behandelt) als char*. Für fast jeden anderes Beispiel von Zeigern ( Employee*, PurchaseOrder*, ...), gibt es jedoch viele Vorteile:

  • Bereich größer als eine einzelne Funktion - Ordnen Sie das Objekt auf dem Heap zu und geben Sie den Zeiger für eine lange Zeit weiter
  • Schnellere Funktionsaufrufe für große Objekte, da Sie nicht die Kopierkosten für die Wertübergabe haben
  • Eine Möglichkeit, einer Funktion das Ändern der an sie übergebenen Parameter zu ermöglichen
  • Sparen Sie Platz und Zeit in Sammlungen, indem Sie nur eine Adresse anstelle eines gesamten Objekts kopieren

In der Tat sind Zeiger so wichtig, dass die meisten Sprachen, die sie scheinbar nicht haben, tatsächlich nur sie haben. Referenztypen in C # und Java sind im Wesentlichen Zeiger, die als feste Objekte getarnt sind.

Jetzt ist die Zeigermanipulation ( p++auf einem Zeiger oder p += delta) eine ganz andere Geschichte. Einige Leute halten es für gefährlich, andere für großartig. Aber das ist noch weiter von Ihrer Frage entfernt.

Kate Gregory
quelle
1

Zeiger können schneller sein und weniger Overhead verursachen, sowohl in Datenstrukturen als auch bei der Reduzierung des Programmausführungs-Footprints. (Bitte beachten Sie das Wort "kann".)

Im Allgemeinen lautet die Regel: Wenn Sie eine Ressource zugewiesen haben, indem Sie entweder Ihre eigene Zuweisung vorgenommen haben oder etwas in Ihrem Namen ausführen lassen, ist es Ihre Aufgabe, sie freizugeben, wenn Sie fertig sind.

Die Last der oben genannten Aufgaben besteht darin, die Verantwortung wieder auf den Entwickler zu übertragen, anstatt sie von der Laufzeit ausführen zu lassen. Dies hat einige weitere Vorteile, da Dinge länger leben oder Grenzen überschreiten oder zu günstigeren Zeiten entsorgt werden können oder nicht das Gewicht eines Müllsammlers tragen müssen.

In exotischen Fällen, die normalerweise Ausnahmen und Umfang beinhalten, gibt es einige Randfälle, bei denen man etwas vorsichtiger sein muss, wenn der Code, der bereinigt wird, vermieden wird. Realistisch gesehen können diese Fälle umgestaltet werden. Wir haben viele Jahrzehnte ohne verwalteten Code gelebt.

Was Zeiger oft "schwer" macht, ist einfach nicht zu verstehen, was auf Hardwareebene vor sich geht. Es ist nichts weiter als Indirektion.

Zeiger bieten Ihnen viel mehr Zugriff, und dies kann sehr hilfreich, clever oder notwendig sein. Sie können überall hin zeigen und es so ziemlich wie alles behandeln. Wenn Sie Ihre gottähnlichen Kräfte zum Guten einsetzen, ist das sehr, sehr gut.

Die Gegenseite ist normalerweise eine Verschwendung, wenn Sie vergessen, etwas freizugeben, oder indem Sie es mehrmals freigeben oder auf etwas verweisen, nachdem es freigegeben wurde, oder wenn Sie etwas verweisen, wenn Sie nicht auf etwas zeigen. Diese Dinge führen oft zu spektakulären Abstürzen, und um ehrlich zu sein, deuten sie normalerweise darauf hin, dass Sie ein logisches Problem haben, anstatt dass Zeiger zerbrechlich sind.

Wenn Sie ein solider Entwickler sind, sollte die Verwendung von Zeigern nicht problematischer sein als jede andere Datenstruktur. Auch hier ist es keine Raketenwissenschaft, und die Leute haben es jahrzehntelang getan, ohne ein Auge zu blinzeln. Es wird heutzutage nur weniger gründlich gelehrt.

Abgesehen davon macht die Konveinenz und die exoitischen Fälle, die eine gute Speicherbereinigung bietet, die Arbeit in einer verwalteten Umgebung umso angenehmer, es sei denn, Sie benötigen Zeiger. Es ist großartig, etwas Speicher abrufen, verwenden und aufgeben zu können, da man weiß, dass es zu einem späteren Zeitpunkt möglicherweise verworfen wird, wenn dies sinnvoll ist. Das ist ein bisschen weniger Code seitens des Codierers im Austausch für eine Laufzeit, die etwas mehr Heben bewirkt.

Walt Stoneburner
quelle
0

Die beste Antwort ist tatsächlich in der Frage enthalten: Zeiger sind für die Programmierung auf niedriger Ebene. Zugegeben, wenn Sie C verwenden, ist das Nichtverwenden von Zeigern wie das Programmieren mit einer Hand hinter dem Rücken, aber die Antwort darauf ist, stattdessen eine höhere Sprache zu verwenden.

Larry Coleman
quelle
-1

Zeiger bieten einen Einblick in die Maschine, die für die interessanteste Programmierung erforderlich ist. Die meisten modernen Sprachen verbergen einfach die grobkörnigen Teile vor Ihnen.

Paul Nathan
quelle