Por que C usa o asterisco para ponteiros?
Simplesmente - porque B sim.
Como a memória é uma matriz linear, é possível interpretar o valor em uma célula como um índice nessa matriz, e o BCPL fornece um operador para essa finalidade. No idioma original, foi escrito rv, e mais tarde !, enquanto B usa o unário *. Portanto, se pé uma célula que contém o índice de (ou endereço de) ou o ponteiro para outra célula, *prefere-se ao conteúdo da célula apontada, como um valor em uma expressão ou como o destino de uma atribuição.
Do desenvolvimento da linguagem C
É isso aí. Nesse ponto, a pergunta é tão desinteressante quanto "por que o python 3 usa .para chamar um método? Por que não ->?" Bem ... porque o Python 2 costuma .chamar um método.
Raramente existe uma linguagem do nada. Ele tem influências e é baseado em algo que veio antes.
Então, por que B não usou !para remover o ponteiro de um ponteiro como o seu BCPL predecessor?
Bem, o BCPL era um pouco prolixo. Em vez de &&ou ||BCPL usado logande logor. Isso ocorreu porque a maioria dos teclados não possui teclas ∧ou ∨não é igual à palavra NEQV(consulte o Manual de referência da BCPL ).
B parece ter sido parcialmente inspirado para reforçar a sintaxe, em vez de ter palavras longas para todos esses operadores lógicos que os programadores faziam com bastante frequência. E assim !a desreferência se tornou *para que !pudesse ser usada para negação lógica. Observe que há uma diferença entre o *operador unário e o *operador binário (multiplicação).
Bem, e outras opções, como ->?
O ->foi levado para o açúcar sintático torno derefrences campo struct_pointer->fieldque é(*struct_pointer).field
Outras opções como <-poderiam criar análises ambíguas. Por exemplo:
foo <- bar
Isso deve ser lido como:
(foo) <- (bar)
ou
(foo) < (-bar)
É muito provável que criar um operador unário composto por um operador binário e outro operador unário tenha problemas, pois o segundo operador unário pode ser um prefixo para outra expressão.
Além disso, é novamente importante tentar reduzir ao mínimo as coisas que estão sendo digitadas. Eu odiaria ter que escrever:
int main(int argc, char->-> argv, char->-> envp)
Isso também se torna difícil de ler.
Outros caracteres podem ter sido possíveis ( @não foram usados até o Objetivo C se apropriar ). Porém, novamente, isso vai para o núcleo de 'C usa *porque B fez'. Por que B não usou @? Bem, B não usou todos os personagens. Não havia nenhum bppprograma (compare cpp ) e outros caracteres estavam disponíveis em B (como o #que mais tarde foi usado pelo cpp).
Se posso arriscar um palpite sobre o porquê - é por causa de onde estão as chaves. De um manual em B :
Para facilitar a manipulação de endereços quando parecer aconselhável, B fornece dois operadores de endereço unário, *e &. &é o operador de endereço, assim &xcomo o endereço de x, supondo que ele tenha um. *é o operador indireto; *xsignifica "use o conteúdo de x como endereço".
Observe que &é o turno-7 e o *turno-8. A proximidade entre eles pode ter sido uma dica para o programador sobre o que eles fazem ... mas isso é apenas um palpite. Alguém teria que perguntar a Ken Thompson sobre por que essa escolha foi feita.
Então, aí está. C é assim porque B era. B é assim porque queria mudar a forma como o BCPL era.
->está sendo usado na linguagem C como um operador de desreferência - ao acessar campos em uma struct:,struct_pointer->fieldque é a abreviação de(*struct_pointer).field.