Was ist der Ursprung des Zählens von Null in Programmiersprachen?

8

Dies ist eine Frage, über die ich mich schon lange gewundert habe (und die mir gestellt wurde).

In (fast? Allen?) Programmiersprachen beginnt ein Index bei Null für ein Array, eine Zeichenfolge usw. Ich erkenne, dass er im Laufe der Zeit zur Konvention wurde und in vielen Sprachen übernommen wurde. Kann jemand auf den Ursprung hinweisen?

Ich dachte, vielleicht hat es damit zu tun, dass alles in Binärform verwurzelt ist. Aber ich bin mir nicht sicher, ob die Idee die Notwendigkeit im Dezimalsystem erfüllt - warum nicht einen Index von 1 beginnen?

Hat jemand historische Kenntnisse in Programmiersprachen, in denen die Entscheidung, Indizes bei Null zu beginnen, möglicherweise erklärt wurde?

Vielen Dank!

EDIT: Die Dijkstra-Schriften sind vom mathematischen Standpunkt aus weiter hilfreich, aber selbst er hat bemerkt, dass nicht alle Sprachen nullindiziert sind. Die Erklärung von WBT macht auch Sinn, warum man basierend auf Speicheradressen mit Null beginnen würde. (Ich weiß, dass einige Sprachen die Indizierung aufgrund der Array-Manipulation etwas anders handhaben.)

Ich suche nicht unbedingt für die , warum (was ich sehr zu schätzen wissen , weil es weiter ein Verständnis hilft) , sondern mehr nach dem Vorbild der als hätte dies die Konvention wurde und / oder ob es kann auf eine bestimmte Sprache zurückgeführt werden.

So erklärt beispielsweise in K & Rs C bei der Erörterung von Array-Indizes K oder R sachlich: "Array-Indizes beginnen in C immer bei Null ..." (S. 22) Später bei der Erörterung einer Funktion zum Verarbeiten von Zeichen Arrays: "... ein nützlicheres Design wäre die Rückgabe der Zeilenlänge oder Null, wenn das Dateiende angetroffen wird. Null ist eine akzeptable Rückgabe am Dateiende, da es sich nie um eine gültige Zeilenlänge handelt." (S. 127)

Basierend auf K & R habe ich festgestellt, dass a) die Konvention von einer anderen Stelle übernommen wurde, sodass C nicht die Inspiration für die Nullindizierung ist und b) es möglicherweise tiefere Gründe für ihre Verwendung gibt, die auf dem zweiten Beispiel basieren. Ich weiß, dass K & R für seine klare Prosa so weithin bekannt ist, und das ist ein weiterer Grund, warum ich es einbeziehe, um ein Beispiel dafür zu geben, was ich gehofft hatte, dass eine andere dokumentierte Sprache den Grund für die Nullindizierung erklären würde.

Ich denke, sowohl WBT als auch btilly bieten gleich gute Gründe; Ich fragte mich, ob jemand, der vielleicht alte Sprachen (vor C?) Kannte, die die Entwurfsentscheidung dokumentierten. Gleichzeitig erkenne ich, dass solche Informationen möglicherweise nicht vorhanden sind.

Mücke
quelle
3
Eine einfache Antwort ist, dass wenn Arrays Zeiger sind, die Basis 0 am logischsten ist. Dann sind Myarray [0] und Myarray + 0 dasselbe Element, und Myarray [1] und Myarray + 1 usw. Betrachten Sie es als einen Versatz von Anfang an. Eine ausführlichere Antwort könnte kommen, also
@ThomasH Das ist nicht ganz "Basis 0". Basis bezieht sich darauf, wie viele eindeutige Symbole unterschiedliche Werte darstellen, bevor eine neue Position in die Zahl eingefügt wird. Die Basis kann gefunden werden, indem herausgefunden wird, was 10-1 in diesem System ist. Basis 10 (dezimal), Basis 2 (binär) und Basis 16 (hex) sind am bekanntesten.
WBT
1
@WBT Das würde man denken, wenn man nur den Titel liest.
@ user6292850 Ich bin damit einverstanden, dass es eine nützliche Referenz ist, aber ich denke nicht, dass es ein Betrug ist.
WBT
3
Dijkstra schrieb dies über Null-Indizes: cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html
Thomas Eding

Antworten:

12

Es geht um Offsets. Sie haben eine Adresse, die auf die Stelle im Speicher verweist, an der das Array beginnt. Um auf ein Element zuzugreifen, multiplizieren Sie den Array-Index mit der Größe des Elements und fügen ihn der Startadresse hinzu, um die Adresse für dieses Element zu finden.

Das erste Element befindet sich am Startpunkt. Sie multiplizieren also die Größe des Elements mit Null , um Null zu erhalten. Dies wird der Startadresse hinzugefügt, um die Position des ersten Elements zu ermitteln.

Die Konvention verbreitete sich, weil Programmierer anfingen, in sehr einfachen Sprachen zu arbeiten, in denen Speicheradressen direkt manipuliert wurden und sich in den meisten Fällen von dort aus aufbauten, wobei bei jedem Schritt dieselbe Konvention beibehalten wurde, damit sie nicht neu lernen oder fehleranfällig sein mussten, wenn Umschalten zwischen Konventionen. Es ist immer noch wichtig zu verstehen, wie diese Adressierung funktioniert, insbesondere wenn mit untergeordneten Sprachen gearbeitet wird. Ich bin damit einverstanden, dass dies ein Stolperstein für Menschen sein kann, die zuerst lernen, in einer höheren Sprache zu programmieren.

Der Wikipedia-Artikel zu diesem Thema zitiert auch eine allgemeine Maschinenanweisung, die verwendet wird, wenn "rückwärts" gearbeitet und das Ende einer Schleife erkannt wird, nämlich "dekrementieren und springen, wenn Null".

Eine Ausnahme: MATLAB und einige andere Sprachen widersetzten sich dem Trend und gingen mit einem Index ab 1, anscheinend unter dem Eindruck, dass es eine erste Programmiersprache für viele ihrer Zielbenutzer sein würde und dass für diese Leute, beginnend mit 1, mehr macht intuitiver Sinn. Dies führt zu einigen Frustrationen für die (relativ kleine Teilmenge von?) Programmierer, die häufig zwischen Programmiersprachen wechseln, die bei unterschiedlichen Werten zu zählen beginnen.

WBT
quelle
1
Ja. Niemand, der Kontakt mit dem Monteur hatte, würde diese Frage stellen :)
Martin James
4

Die Aussage "In (fast? Allen?) Programmiersprachen beginnt ein Index bei Null" ist einfach nicht korrekt. Diejenigen Sprachen, deren Erbe formal oder informell von C stammt, folgen dieser Konvention. Andere mögen es nicht.

C hat es so gemacht, weil C grundsätzlich als "hochrangiger" Assembler gedacht war. Dies belastete den Programmierer erheblich, während der Compiler und die Maschine in anderen Sprachen das schwere Heben übernahmen. Zu der Zeit, als C entwickelt wurde, war 1-basiertes Zählen die Norm, aber es wurde als zu viel Arbeit für den Compiler angesehen, dass der Compiler diese dumme zusätzliche 1 im Auge behalten musste.

C ++ hat es von C erhalten, weil C ++ abwärtskompatibel (einige könnten sagen, fehlerkompatibel) mit C sein muss. Java hat es von C. Sprachen erhalten, die von C-Programmierern entwickelt wurden, ohne dass irgendetwas anderem C ausgesetzt war, weil sie es auch waren wollte bei anderen C-Programmierern beliebt sein oder sie wussten keine andere Möglichkeit, dies zu tun.

FORTRAN, das vor fast allem anderen da draußen ist, begann bei 1, weil Ingenieure, Mathematiker und Wissenschaftler seit Jahrtausenden mit 1 zählen. (Dies ermöglicht einen sehr präzisen, sehr schönen Algorithmus für das 8-Königinnen-Problem.) MATLAB kopierte FORTRAN, da es sich an fast genau dieselbe Benutzergemeinschaft richtete.

Bei PASCAL muss der Programmierer tatsächlich angeben, wo er beginnt und endet, sodass beispielsweise ein Array definiert werden kann, dessen Indizes beispielsweise zwischen -7 und +7 liegen. Ada folgte PASCAL. (Die Erwähnung von Ada sollte genau dort für mindestens drei Abstimmungen gut sein.)

Ich glaube, COBOL hat bei 1 angefangen, aber ich erinnere mich nicht sicher, und ich habe nicht die Absicht, einige sehr schmerzhafte Erinnerungen aufzufrischen, weil Buchhalter wie Ingenieure, Wissenschaftler und Mathematiker bei 1 anfangen zu zählen.

Es ist meine ferne Erinnerung, dass PL / I Ihnen erlaubt hat, zu starten und zu stoppen, wo immer Sie möchten. Vollständige Offenlegung: Ich habe noch nie PL / I-Codierung durchgeführt, nur ein Buch überflogen, und ich habe nicht die Absicht, dies zu ändern.

Ich habe während meiner kurzen Exposition nie Arrays in GPSS (IBMs diskretes Ereignissimulationspaket) verwendet, daher kann ich Ihnen nicht sagen, wie GPSS dies getan hat.

Assemblersprachen beginnen normalerweise bei 0, da Arrays traditionell als Startadresse und Versatz zur Startadresse definiert werden. (Dies ist nicht immer der Fall. Der IBM 1130 Executive verfügte über eine große residente Vektortabelle, deren "Startadresse" sich tatsächlich in der Mitte der Tabelle befand. Dies geschah, weil die indizierte 1130-Adressierung signierte Offsets zuließ, bei denen Offsets beginnen mussten Null hätte die Hälfte der möglichen Größe des Tisches weggeworfen, und dieser Tisch MUSS groß sein.)

John R. Strohm
quelle
0

Ich versuche eine kurze Antwort.

Das Zählen von Null ist nicht nur in Programmiersprachen, sondern allgemein in der Mathematik beliebt.

Das Zählen ist viel älter als die Null. Da die Null- und Positionsnotation erfunden wurde, zählt jeder 10s, 100s, 1000s usw. von Null: Es ist die neue niedrigste Ziffer. Das Zählen von Einheiten von Null bringt auch einige Konsistenzvorteile, insbesondere bei halboffenen Intervallen und (mehrdimensionalen) Arrays. Weitere Details und Beispiele finden Sie unter den Links auf der rechten Seite und unter https://en.wikipedia.org/wiki/Zero-based_numbering

März
quelle
1
Zahlen gehen von 0 bis 9, nicht von 1 bis 10.
Ignacio Soler Garcia
Nach meiner Erfahrung sind Indizes von 1 bis n in der Mathematik beliebter als Indizes von 0 bis n-1.
CodesInChaos
-3

Jede mögliche Zählkonvention wurde ausprobiert. Die Zählung ab Null ist dominant geworden, da die Alternativen tendenziell unfallanfälliger sind.

Unter https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html finden Sie eine Erklärung, warum diese Version besser funktioniert.

Übrigens
quelle
2
Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert. - Aus dem Rückblick
Vinoth Krishnan
6
"Jede mögliche Zählkonvention wurde ausprobiert." Umfasst das diejenige, die bei - e beginnt und um Einheiten von π inkrementiert ?
WBT