it-swarm.dev

Müssen die jungen Köpfe die Zeigerkonzepte lernen?

Warum hat der C-Master Dennis Ritchie Zeiger in C eingeführt? Und warum haben die anderen Programmiersprachen wie VB.NET oder Java oder C # sie beseitigt? Ich habe einige Punkte in Google gefunden und möchte auch Ihre Kommentare anhören. Warum beseitigen sie Zeigerkonzepte? in modernen Sprachen?

Die Leute sagen, C ist die Grundsprache und Zeiger sind das Konzept, das C mächtig und herausragend macht und C immer noch dazu bringt, mit moderneren Sprachen zu konkurrieren. Warum haben sie dann Zeiger in moderneren Sprachen entfernt?

Denken Sie, dass die Kenntnis von Zeigern für neue Programmierer immer noch wichtig ist? Die Leute benutzen heutzutage VB.NET oder Java, das fortgeschrittenere Funktionen als C unterstützt (und keine Zeigerkonzepte verwendet), und viele Leute, wie ich jetzt sehe (meine Freunde), wählen diese Sprachen, die C ignorieren, da sie erweiterte Funktionen unterstützen. Ich fordere sie auf, mit C zu beginnen. Sie sagen, es sei eine Verschwendung, die Konzepte von Zeigern zu lernen, wenn Sie die erweiterten Funktionen in VB.NET oder Java) ausführen = die in C nicht möglich sind.

Was denken Sie?

Aktualisiert :

Die Kommentare, die ich bei Google gelesen habe, sind:

  1. Die früheren Computer waren zu langsam und nicht optimiert.

  2. Die Verwendung von Zeigern ermöglicht den direkten Zugriff auf eine Adresse. Dies spart Zeit, anstatt eine Kopie davon in Funktionsaufrufen zu erstellen.

  3. Die Sicherheit ist bei Verwendung von Zeigern erheblich schlechter, weshalb Java und C # haben sie nicht enthalten.

Diese und einige mehr, was ich gefunden habe. Ich brauche noch einige wertvolle Antworten. Das wäre sehr dankbar.

92
niko

Damals arbeiteten Entwickler viel näher am Metall. C war im Wesentlichen ein Ersatz auf höherer Ebene für Assembly, der fast so nah wie möglich an der Hardware liegt. Daher war es selbstverständlich, dass Sie Zeiger benötigten, um Codierungsprobleme effizient zu lösen. Zeiger sind jedoch scharfe Werkzeuge, die bei unachtsamer Verwendung großen Schaden anrichten können. Die direkte Verwendung von Zeigern eröffnet auch die Möglichkeit für viele Sicherheitsprobleme, die damals kein Problem darstellten (1970 bestand das Internet aus etwa ein paar Dutzend Maschinen an mehreren Universitäten, und es wurde nicht einmal so genannt ...), wurde aber seitdem immer wichtiger. Heutzutage sind höhere Sprachen bewusst darauf ausgelegt, rohe Speicherzeiger zu vermeiden.

Zu sagen, dass "fortgeschrittene Dinge in VB.Net oder Java sind in C nicht möglich"), gelinde gesagt, eine sehr begrenzte Sichtweise zeigt :-)

Zuallererst sind alle diese Sprachen (sogar die Versammlung) vollständig, so dass theoretisch alles möglich ist, was in einer Sprache möglich ist. Denken Sie nur daran, was passiert, wenn ein Teil von VB.Net oder Java Code kompiliert und ausgeführt wird: Schließlich wird er in Maschinencode übersetzt (oder diesem zugeordnet), da dies das einzige ist, was Die Maschine versteht. In kompilierten Sprachen wie C und C++ können Sie tatsächlich den gesamten Maschinencode, der dem ursprünglichen Quellcode der höheren Ebene entspricht, als eine oder mehrere ausführbare Dateien/Bibliotheken erhalten. In VM = basierte Sprachen, es ist schwieriger (und möglicherweise nicht einmal möglich), die gesamte äquivalente Maschinencodedarstellung Ihres Programms zu erhalten, aber schließlich befindet es sich irgendwo in den tiefen Nischen des Laufzeitsystems und der JIT.

Nun ist es natürlich eine ganz andere Frage, ob eine Lösung in einer bestimmten Sprache möglich ist. Kein vernünftiger Entwickler würde anfangen, eine Web-App in Assembly zu schreiben :-) Aber es ist nützlich zu bedenken, dass die meisten oder alle dieser höheren Sprachen auf einer großen Menge an Laufzeit- und Klassenbibliothekscode basieren, einem großen Teil davon die in einer niedrigeren Sprache implementiert ist, typischerweise in C.

Um auf die Frage zu kommen,

Halten Sie das Wissen über Hinweise auf die Jugendlichen [...] für wichtig?

Das Konzept hinter Zeigern ist Indirektion. Dies ist ein sehr wichtiges Konzept und meiner Meinung nach sollte jeder gute Programmierer es auf einer bestimmten Ebene verstehen. Selbst wenn jemand ausschließlich mit höheren Sprachen arbeitet, sind Indirektion und Referenzen immer noch wichtig. Wenn Sie dies nicht verstehen, können Sie nicht in der Lage sein, eine ganze Klasse sehr leistungsfähiger Tools zu verwenden, was die Fähigkeit zur Problemlösung auf lange Sicht ernsthaft einschränkt.

Meine Antwort lautet also: Ja, wenn Sie ein wirklich guter Programmierer werden möchten, müssen Sie auch die Zeiger verstehen (sowie die Rekursion - dies ist der andere typische Stolperstein für angehende Entwickler). Möglicherweise müssen Sie nicht damit beginnen - ich denke nicht, dass C heutzutage als Muttersprache optimal ist. Aber irgendwann sollte man sich mit Indirektion vertraut machen. Ohne sie können wir nie verstehen, wie die von uns verwendeten Tools, Bibliotheken und Frameworks tatsächlich funktionieren. Und ein Handwerker, der nicht versteht, wie seine Werkzeuge funktionieren, ist sehr begrenzt. Fair genug, man kann es auch in höheren Programmiersprachen verstehen. Ein guter Lackmustest ist die korrekte Implementierung einer doppelt verknüpften Liste. Wenn Sie dies in Ihrer Lieblingssprache tun können, können Sie behaupten, dass Sie die Indirektion gut genug verstehen.

Aber wenn nicht für irgendetwas anderes, sollten wir es tun, um Respekt für die Programmierer der alten Zeit zu lernen, die es geschafft haben, mit den lächerlich einfachen Werkzeugen, die sie hatten (im Vergleich zu dem, was wir jetzt haben), unglaubliche Dinge zu bauen. Wir stehen alle auf den Schultern von Riesen, und es tut uns gut, dies anzuerkennen, anstatt so zu tun, als wären wir selbst die Riesen.

129
Péter Török

Ich denke, Sie müssen sich unterscheiden.

Java und andere übergeordnete Sprachen haben keine Zeiger entfernt. Was sie taten, war, einfache Zeigerarithmetik zu entfernen.

Tatsächlich erlaubt Java erlaubt immer noch eine geschützte und eingeschränkte Zeigerarithmetik: den Array-Zugriff. Im einfachen alten C ist der Array-Zugriff nichts anderes als Dereferenzierung. Es ist eine andere Notation, ein syntaktischer Zucker, wenn Sie so wollen, um klar zu kommunizieren, was Sie tun.
Dennoch entspricht array[index]*(array+index). Aus diesem Grund entspricht es auch index[array], Obwohl einige C-Compiler Ihnen möglicherweise eine Warnung geben, wenn Sie dies tun.
Folglich entspricht pointer[0]*pointer. Das liegt einfach daran, dass der "Zeiger auf ein Array" die Adresse des ersten Eintrags des Arrays ist und die Adressen der nachfolgenden Elemente durch Hinzufügen des Index berechnet werden.

In Java gibt es keine einfachen Zeigerarithmetiken (Referenzieren und Dereferenzieren) mehr. Es gibt jedoch Zeiger. Sie nennen sie Referenzen, aber es ändert nichts daran, was es ist. Und der Array-Zugriff ist immer noch genau dasselbe: Sehen Sie sich die Adresse an, fügen Sie den Index hinzu und verwenden Sie diesen Speicherort. In Java wird jedoch geprüft, ob dieser Index innerhalb der Grenzen des ursprünglich zugewiesenen Arrays liegt. Wenn nicht, wird eine Ausnahme ausgelöst.

Der Vorteil des Ansatzes Java) besteht nun darin, dass Sie keinen Code haben, der nur blind beliebige Bytes in beliebige Speicherorte schreibt. Dies verbessert die Sicherheit und auch die Sicherheit, denn wenn Sie nicht prüfen Pufferüberläufe und so, die Laufzeit wird es für Sie tun.

Der Nachteil dabei ist, dass es einfach weniger mächtig ist. Es ist möglich, in C speichersicher zu programmieren. Es ist unmöglich, von der Geschwindigkeit und den Möglichkeiten einer unsicheren Programmierung in Java zu profitieren.

Zeiger oder Zeigerarithmetik sind eigentlich nichts Schwieriges. Sie werden normalerweise nur auf verschlungene Weise erklärt, während ein Zeiger nur ein Index für ein riesiges Array (Ihren Speicherplatz) ist. Wenn Sie nur auf einen Wert verweisen, erhalten Sie den Index, wo Sie ihn finden können. Bei der Dereferenzierung wird lediglich nachgeschlagen der Wert bei einem bestimmten Index. (Dies ist nur ein wenig vereinfacht, da nicht berücksichtigt wird, dass die Werte im Speicher je nach Typ unterschiedlich groß sind. Dies ist jedoch eher ein umständliches Detail als ein Teil des eigentlichen Konzepts.)

IMHO, jeder in unserem Job sollte das verstehen können, oder sie sind einfach auf dem falschen Gebiet.

39
back2dos

Das Konzept der Zeiger ist im allgemeinen Wissensbestand der Computerprogrammierung wichtig. Das Verständnis des Konzepts ist gut für angehende Programmierer oder Programmierer jeder Sprache, auch wenn die Sprache es nicht direkt unterstützt.

Zeiger werden in Datenstrukturen (verknüpfte Listen) und im Datenbankdesign (Fremdschlüssel) verwendet.

Sprachen wie VB und C # können Daten durch "Referenz" an Methoden übergeben, die als Zeigertyp betrachtet werden können.

Für die Effizienz von Algorithmen ist es immer noch wichtig zu verstehen, wo Daten im Speicher zugeordnet sind (Stapel vs. Heap).

Die richtigen Grundlagen zu lernen ist meiner Meinung nach wichtig.

24
NoChance

Ja, ja, ja, ja und ja !!!

Wenn Sie die Grundlagen nicht kennen, werden Sie NIEMALS in der Lage sein, die wirklich harten, seltsamen, schwierigen und komplizierten Probleme zu lösen, die Ihnen in den Weg kommen.

Und wenn Sie die Grundlagen wirklich gut verstehen, sind Sie auf dem Arbeitsmarkt VIEL marktfähiger.


Ich habe einmal mit einem Jungen gearbeitet, der seit 10 Jahren programmiert und keine Ahnung hatte, wie Zeiger funktionieren. Ich (viel jünger) verbrachte Stunden an einem Whiteboard, um ihn zu unterrichten. Das öffnete meine Augen. Er hatte NO IDEA über so viele grundlegende Dinge.

Wissen Sie so viel wie möglich.

19
quickly_now

Ja, Verständnis ist wichtig.

Vor ein paar Monaten habe ich in C # programmiert und wollte eine Kopie einer Liste erstellen. Natürlich habe ich NewList = OldList; und begann dann, NewList zu ändern. Als ich versuchte, beide Listen auszudrucken, waren beide gleich, da NewList nur ein Zeiger auf OldList und keine Kopie war, also änderte ich tatsächlich OldList all entlang. Ich brauchte nicht lange, um das herauszufinden, aber einige meiner Klassenkameraden waren nicht so schnell und mussten erklärt werden, warum dies geschieht.

Beispiel:

List<int> a = new List<int>();
a.Add(2);
a.Add(9);
a.Add(8);
a.Add(1);
List<int> b = new List<int>();
b = a; //Does not make a copy, b is just a synonym!
b.Sort();
for (int i = 0; i < a.Count; i++)
{
    Console.WriteLine("a: " + a[i] + " b: " + b[i]);
}

Und natürlich ist das Ergebnis so:

a: 1 b: 1
a: 2 b: 2
a: 8 b: 8
a: 9 b: 9

Zu wissen, wie man sie benutzt, ist nicht so wichtig, aber es ist entscheidend, sie zu verstehen!

18
Bojan Kogoj

Warum hat der C-Meister Dennis Ritchie Zeiger in C eingeführt?

Weil Zeiger ein sehr leistungsfähiger Mechanismus sind, der auf viele Arten verwendet werden kann.

Und warum haben die anderen Programmiersprachen wie VB.NET oder Java oder C # sie eliminiert?

Weil Zeiger ein sehr gefährlicher Mechanismus sind, der auf viele Arten missbraucht werden kann.

Ich denke, Programmierer sollten etwas über Zeiger lernen, aber aus pädagogischer Sicht ist es unklug, sie frühzeitig einzuführen. Der Grund ist, dass sie für so viele verschiedene Zwecke verwendet werden, dass es für Anfänger schwierig ist zu sagen, warum Sie unter bestimmten Umständen einen Zeiger verwenden.

Hier ist eine unvollständige Liste, wofür Zeiger verwendet werden:

  • dynamische Zuordnung (new T)
  • rekursive Datenstrukturen (struct T { T* next; /* ... */ };)
  • iteratoren über Arrays (for (T* p = &a[0]; p != &a[0] + n; ++p) { ... })
  • gemeinsamer Zugriff auf Objekte (T* new_pointer = existing_pointer;)
  • subtyp-Polymorphismus (T* pointer_to_base = pointer_to_derived;)
  • legacy-Aufruf als Referenz (mutate(&object);)
  • optionale Typen (if (p) { /* ... */ })

Beachten Sie, dass die Verwendung eines einzigen Mechanismus für alle diese Konzepte sowohl die Kraft und Eleganz des erfahrenen Programmierers als auch das große Verwirrungspotential für jemanden zeigt, der neu in der Programmierung ist.

14
fredoverflow

Zeiger auf das Konzept! = Zeiger auf die Arithmetik! = Zeiger auf die Syntax

Das erste ist immer wichtig, wenn Sie ein Verständnis für tiefe/flache Kopien benötigen, als Referenz übergeben/als Wert übergeben usw. Die beiden anderen sind nur dann wichtig, wenn Ihre Sprache Sie es erlaubt, sie zu verwenden.

14
Alien Life Form

Warum? Mit Forms Designer und Codegenerator können Sie ein riesiges System schreiben. Ist es nicht ausreichend? (Ironie)

Und jetzt im Ernst, Zeiger sind in vielen Bereichen kein entscheidender Bestandteil der Programmierung, aber sie ermöglichen es den Menschen zu verstehen, wie die Interna funktionieren. Und wenn wir niemanden haben, der versteht, wie Interna funktionieren, wird es eine Situation geben, in der SQL2020, Windows 15 und Linux 20.04 in eine virtuelle Maschine geschrieben werden, die über 30 Abstraktionsebenen mit über IDE generiertem Code in JavaScript ausgeführt wird .

Das möchte ich definitiv nicht sehen.

Also ja, das müssen sie definitiv!

12
Coder

Weder Java noch C # eliminierte Zeiger, sie haben Referenzen, die fast gleich sind. Was eliminiert wurde, ist Zeigerarithmetik, die in einem Einführungskurs weggelassen werden kann.
Ohne das Konzept von Zeigern oder Referenzen könnte keine nicht triviale Anwendung erfolgen, daher lohnt es sich zu lehren (ohne sie könnte keine dynamische Speicherzuweisung erfolgen).

Betrachten Sie Folgendes in C++ und Java, und ich denke, dass es in C # nicht sehr unterschiedlich ist:
aClass *x = new aClass();
aClass x = new aClass();
Es gibt nicht wirklich zu viele Unterschiede zwischen Zeigern und Referenzen, oder?
Zeigerarithmetik sollte vermieden werden, sofern dies nicht erforderlich ist und wenn mit High-Level-Modellen programmiert wird, sodass dort keine großen Probleme auftreten.

7
Petruza

Der professionelle Programmierer sollte Zeiger beherrschen.

Die Leute, die Programmierung kennenlernen wollen, sollten etwas über ihre Existenz und ihre Auswirkungen lernen, sie aber nicht unbedingt verwenden.

Die Leute, die persönliche Probleme durch Programmierung lösen wollen (wie ich, die viele Python Skripte) verwenden), könnten sie überhaupt ignorieren.

Nun, das ist meine Meinung ...; o)

6
heltonbiker

Absufreakinglutely JA ! Jeder, der programmiert, muss Zeiger und Indirektion verstehen.

Zeiger sind, wie eine große Menge an Datenzugriff in allen Sprachen durchgeführt wird. Zeiger sind ein Hardwaremerkmal aller Mikroprozessoren. Hochsprachen wie Java, VB & C # blockieren im Wesentlichen den direkten Zugriff auf Zeiger von Benutzern der Sprache mit Referenzen. Referenzen verweisen auf Objekte über das Speicherverwaltungsschema der Sprache (könnte ein Zeiger mit sein Metadaten oder nur eine Zahl für eine Speichertabelle, zum Beispiel).

Das Verständnis der Funktionsweise von Zeigern ist von grundlegender Bedeutung , um zu verstehen, wie Computer tatsächlich funktionieren. Zeiger sind außerdem flexibler und leistungsfähiger als Referenzen.

Der Grund, warum Arrays bei Index Null beginnen, liegt beispielsweise darin, dass Arrays für die Zeigerarithmetik eigentlich eine Abkürzung sind. Ohne zu lernen, wie Zeiger funktionieren, erhalten viele anfängliche Programmierer keine Arrays.

int a, foo[10];
foo[2] = a;

Zeile 2 in der Zeigerarithmetik wäre:

*(foo + sizeof(int) * 2) = a;

Ohne das Verstehen von Zeigern kann man die Speicherverwaltung, den Stapel, den Heap oder sogar Arrays nicht verstehen! Zusätzlich muss man Zeiger und Dereferenzierungen verstehen, um zu verstehen, wie Funktionen und Objekte übergeben werden.

TL: DR: Das Verstehen von Zeigern ist von grundlegender Bedeutung für das Verständnis, dass Computer tatsächlich funktionieren .

3
CyberSkull

Variable Adresszeiger sind ein spezieller Fall des allgemeineren Konzepts der Indirektion. Indirektion wird in den meisten (allen?) Modernen Sprachen in vielen Konstrukten wie Delegaten und Rückrufen verwendet. Wenn Sie das Konzept der Indirektion verstehen, wissen Sie, wann und wie Sie diese Tools am besten verwenden können.

3
Dave Nay

Ich denke, es läuft darauf hinaus, dass die Notwendigkeit, mit Zeigern umzugehen, wegfiel, da Programmierer sich weniger mit der direkten Hardware befassten, auf der sie liefen. Beispiel: Zuweisen einer verknüpften Listendatenstruktur auf eine Weise, die perfekt zu der Sequenz von 640-Byte-Speichermodulen passt, über die die spezielle Hardware verfügt.

Der manuelle Umgang mit Zeigern kann fehleranfällig sein (was zu Speicherlecks und ausnutzbarem Code führt) und ist zeitaufwändig, um die richtigen Ergebnisse zu erzielen. Java und C # usw. verwalten jetzt Ihren Speicher und Ihre Zeiger für Sie über ihre virtuellen Maschinen (VMs). Dies ist wohl weniger effizient als die Verwendung von C/C++, obwohl sich die VMs ständig verbessern .

C (und C++) sind nach wie vor weit verbreitete Sprachen, insbesondere in den Bereichen High Performance Computing, Gaming und eingebettete Hardware. Ich bin persönlich dankbar, dass ich etwas über Zeiger gelernt habe, da der Übergang zu Javas Referenzen (ein ähnliches Konzept wie Zeiger) sehr einfach war und ich nicht verloren ging, als ich meine erste NullPointerException sah (die eigentlich als NullReferenceException bezeichnet werden sollte, aber ich schweife ab). .

Ich würde empfehlen, etwas über das Konzept von Zeigern zu lernen, da diese immer noch viele Datenstrukturen usw. unterstützen. Wählen Sie dann eine Sprache aus, in der Sie gerne arbeiten, und wissen Sie, dass Sie wissen, was wirklich vor sich geht, wenn so etwas wie eine NPE auftaucht .

2
Martijn Verburg

Dies ist die objektive Wahrheit:

Einige Sprachen unterstützen den direkten Speicherzugriff (Zeiger), andere nicht. Für jeden Fall gibt es gute Gründe.

  1. Wie hier jemand sagte, war die automatische Speicherverwaltung in den Tagen von C nicht so aufwändig wie heute. Und die Leute waren sowieso daran gewöhnt. Die guten Programmierer hatten damals ein viel tieferes Verständnis für Computerprogramme als für unsere Generation (ich bin 21). Sie haben Lochkarten verwendet und Tage auf eine Kompilierungszeit auf dem Mainframe gewartet. Sie wussten wahrscheinlich, warum jedes Bit in ihrem Code existierte.

  2. Der offensichtliche Vorteil von Sprachen wie C besteht darin, dass Sie eine genauere Kontrolle über Ihr Programm haben. Wann brauchen Sie es heutzutage tatsächlich ? Nur wenn Sie Infrastrukturanwendungen erstellen, z. B. Betriebssystemprogramme und Laufzeitumgebungen. Wenn Sie nur gute, schnelle, robuste und zuverlässige Software entwickeln möchten, ist die automatische Speicherverwaltung meistens die bessere Wahl.

  3. Tatsache ist, dass der direkte Speicherzugriff im Laufe der Softwareentwicklungsgeschichte größtenteils missbraucht wurde. Die Leute hatten Programme erstellt, bei denen Speicher verloren ging, und waren aufgrund der redundanten Speicherzuweisung tatsächlich langsamer (in C ist es einfach und üblich, den virtuellen Speicherplatz des Prozesses für jede einzelne Zuweisung zu erweitern).

  4. Heutzutage leisten virtuelle Maschinen/Laufzeiten einen viel besseren Job als 99% der Programmierer beim Zuweisen und Freigeben von Speicher. Darüber hinaus bieten sie Ihnen zusätzliche Flexibilität im Ablauf Ihres Programms, da Sie (meistens) nicht damit beschäftigt sind, den zugewiesenen Speicher zum richtigen Zeitpunkt und am richtigen Ort freizugeben.

  5. Was das Wissen betrifft. Ich finde es bewundernswert, dass Programmierer wissen, wie die Umgebungen, in denen sie programmieren, implementiert sind. Nicht unbedingt bis ins kleinste Detail, aber das große Ganze.

Ich denke, dass es interessant ist zu wissen, wie Zeiger (zumindest) funktionieren. Das gleiche wie zu wissen, wie Polymorphismus implementiert wird. Woher und wie bezieht Ihr Prozess sein Gedächtnis? Dies sind Dinge, die mich persönlich immer interessiert haben. Ich kann ehrlich sagen, dass sie mich zu einem besseren Programmierer gemacht haben, aber ich kann nicht sagen, dass sie eine pädagogische Notwendigkeit für jeden sind, der ein guter Programmierer werden möchte. In beiden Fällen wird es Sie oft besser bei Ihrer Arbeit machen, wenn Sie mehr wissen.

  1. So wie ich es sehe, müssen Sie sich auf die richtigen Entwurfs- und Implementierungstechniken konzentrieren, wenn Sie lediglich aufgefordert werden, eine Anwendung in Java oder C # oder so ähnlich) zu erstellen. Testbarer Code , sauberer Code, flexibler Code. In dieser Reihenfolge.

Denn selbst wenn Sie nicht alle kleinen Details kennen, kann jemand, der dies tut, das, was Sie erstellt haben, in etwas ändern, das einfach eine bessere Leistung erbringt. Und das ist oft keine schwierige Aufgabe, wenn Sie ein korrektes, sauberes und überprüfbares Design haben (und das ist normalerweise der größte Teil der Arbeit).

Wenn ich ein Interviewer wäre, der jemanden für eine Hochsprachenanwendung einstellen möchte, wären dies die Dinge, die mich am meisten interessieren würden.

Niedriges Wissen ist ein Bonus. Es ist gut zum Debuggen und gelegentlich zum Erstellen etwas besserer Lösungen. Es macht Sie beruflich zu einer interessanten Person. Es gewährt Ihnen etwas Respekt an Ihrem Arbeitsplatz.

Aber in der heutigen Welt ist es keine heilige Anforderung.

0
Yam Marcovic