É necessário algum tipo de indireção para programas complexos (por exemplo, estruturas de dados recursivas ou de tamanho variável). No entanto, não é necessário implementar esse indireto por meio de ponteiros.
A maioria das linguagens de programação de alto nível (ou seja, não o Assembly) é bastante segura para a memória e não permite acesso irrestrito ao ponteiro. A família C é a mais estranha aqui.
C evoluiu de B, que era uma abstração muito fina sobre a montagem bruta. B tinha um único tipo: a palavra. A palavra pode ser usada como um número inteiro ou como ponteiro. Esses dois são equivalentes quando toda a memória é visualizada como uma única matriz contígua. C manteve essa abordagem bastante flexível e continuou a apoiar aritmética de ponteiro inerentemente insegura. Todo o sistema de tipos de C é mais uma reflexão tardia. Essa flexibilidade no acesso à memória tornou o C muito adequado para seu objetivo principal: criar um protótipo do sistema operacional Unix. É claro que o Unix e o C se mostraram bastante populares, de modo que o C também é usado em aplicativos em que essa abordagem de baixo nível da memória não é realmente necessária.
Se olharmos para as linguagens de programação que vieram antes do C (por exemplo, Fortran, dialetos de Algol, incluindo Pascal, Cobol, Lisp, ...), alguns deles suportam ponteiros do tipo C. Notavelmente, o conceito de ponteiro nulo foi inventado para o Algol W em 1965. Mas nenhuma dessas linguagens tentou ser uma linguagem eficiente de sistemas de baixa abstração do tipo C: o Fortran era destinado à computação científica, o Algol desenvolveu alguns conceitos bastante avançados, o Lisp foi mais um projeto de pesquisa do que uma linguagem de nível industrial, e Cobol estava focado em aplicativos de negócios.
A coleta de lixo existe desde o final dos anos 50, ou seja, bem antes de C (início dos anos 70). O GC exige que a segurança da memória funcione corretamente. Os idiomas antes e depois de C usavam o GC como um recurso normal. É claro que isso torna uma linguagem muito mais complicada e possivelmente mais lenta, o que era especialmente perceptível na época dos mainframes. As linguagens de GC tendem a ser orientadas para a pesquisa (por exemplo, Lisp, Simula, ML) e / ou requerem estações de trabalho poderosas (por exemplo, Smalltalk).
Com computadores menores e mais poderosos, a computação em geral e as linguagens de GC se tornaram mais populares. Para aplicações em tempo não real (e algumas vezes até então), o GC é agora a abordagem preferida. Mas os algoritmos de GC também foram objeto de intensa pesquisa. Como alternativa, uma melhor segurança de memória sem GC também foi desenvolvida, especialmente nas últimas três décadas: inovações notáveis são RAII e indicadores inteligentes no C ++ e no verificador vitalício do sistema / empréstimo da Rust.
O Java não inovou por ser uma linguagem de programação segura para a memória: ela basicamente utilizou a semântica da linguagem GCt, Smalltalk, segura para a memória e combinou-as com a sintaxe e a digitação estática do C ++. Foi então comercializado como um C / C ++ melhor e mais simples. Mas é apenas superficialmente um descendente de C ++. A falta de indicadores de Java é devida muito mais ao modelo de objeto Smalltalk do que à rejeição do modelo de dados C ++.
Portanto, linguagens "modernas" como Java, Ruby e C # não devem ser interpretadas como superando os problemas de ponteiros brutos como em C, mas devem ser vistas como extraídas de muitas tradições - incluindo C, mas também de linguagens mais seguras como Smalltalk, Simula, ou Lisp.