Warum verwendet C das Sternchen für Zeiger?
Einfach - weil B es tat.
Da der Speicher ein lineares Array ist, kann der Wert in einer Zelle als Index in diesem Array interpretiert werden, und BCPL stellt zu diesem Zweck einen Operator bereit. In der Originalsprache wurde es geschrieben rv
und später !
, während B das Unäre verwendet *
. Wenn p
also eine Zelle den Index (oder die Adresse) einer anderen Zelle enthält oder auf eine andere Zelle zeigt, *p
bezieht sie sich entweder als Wert in einem Ausdruck oder als Ziel einer Zuweisung auf den Inhalt der Zelle, auf die verwiesen wird.
Aus der Entwicklung der C-Sprache
Das ist es. An dieser Stelle ist die Frage so uninteressant wie "Warum wird in Python 3 .
eine Methode aufgerufen? Warum nicht ->
?". Nun ... weil Python 2 verwendet .
, um eine Methode aufzurufen.
Selten existiert eine Sprache aus dem Nichts. Es hat Einflüsse und basiert auf etwas, das vorher kam.
Warum hat B also nicht !
wie sein Vorgänger BCPL einen Zeiger für die Dereferenzierung verwendet?
Nun, BCPL war ein bisschen wortreich. Anstelle von &&
oder ||
BCPL verwendet logand
und logor
. Dies lag daran, dass die meisten Tastaturen keine ∧
oder ∨
Tasten haben und nicht gleich dem Wort war NEQV
(siehe BCPL-Referenzhandbuch ).
B scheint teilweise inspiriert worden zu sein, die Syntax zu verschärfen, anstatt lange Wörter für all diese logischen Operatoren zu haben, die Programmierer ziemlich häufig taten. Und so wurde !
für die Dereferenzierung *
, dass !
für die logische Verneinung verwendet werden konnte. Beachten Sie, dass es einen Unterschied zwischen dem unären *
und dem binären *
Operator gibt (Multiplikation).
Wie sieht es mit anderen Optionen aus ->
?
Das ->
wurde für syntaktischen Zucker um Felddifferenzen genommen, struct_pointer->field
das ist(*struct_pointer).field
Andere Optionen wie <-
können zu mehrdeutigen Parsings führen. Beispielsweise:
foo <- bar
Ist das zu lesen als:
(foo) <- (bar)
oder
(foo) < (-bar)
Es ist sehr wahrscheinlich, dass ein unärer Operator, der aus einem binären Operator und einem anderen unären Operator besteht, Probleme verursacht, da der zweite unäre Operator ein Präfix für einen anderen Ausdruck sein kann.
Darüber hinaus ist es wieder wichtig zu versuchen, die häufig getippten Dinge auf ein Minimum zu beschränken. Ich würde es hassen , schreiben zu müssen:
int main(int argc, char->-> argv, char->-> envp)
Dies wird auch schwer zu lesen.
Möglicherweise waren auch andere Zeichen möglich (die @
wurden erst verwendet, nachdem sie von Ziel C übernommen wurden ). Dies geht jedoch wieder zum Kern von "C verwendet, *
weil B es getan hat". Warum hat B nicht verwendet @
? Nun, B hat nicht alle Zeichen verwendet. Es gab kein bpp
Programm (vergleiche cpp ) und andere Zeichen waren in B verfügbar (wie sie #
später von cpp verwendet wurden).
Wenn ich eine Vermutung wagen darf, warum - liegt es daran, wo sich die Schlüssel befinden. Aus einem Handbuch zu B :
Um die Manipulation von Adressen zu erleichtern, wenn es ratsam erscheint, stellt B zwei unäre Adressoperatoren zur Verfügung, *
und &
. &
Ist der Adressoperator so &x
ist die Adresse von x
, vorausgesetzt, es hat eine. *
ist der Indirektionsoperator; *x
bedeutet "benutze den Inhalt von x als Adresse."
Beachten Sie, dass &
Shift-7 und *
Shift-8 ist. Ihre Nähe zueinander mag für den Programmierer ein Hinweis darauf gewesen sein, was sie tun ... aber das ist nur eine Vermutung. Man müsste Ken Thompson fragen, warum diese Wahl getroffen wurde.
Also, da hast du es. C ist so, weil B war. B ist so, weil es ändern wollte, wie BCPL war.
->
dass in der Sprache C als Dereferenzierungsoperator verwendet wird - beim Zugriff auf Felder in einer struct :struct_pointer->field
, die Abkürzung für(*struct_pointer).field
.