È necessario un qualche tipo di riferimento indiretto per programmi complessi (ad esempio strutture di dati ricorsive o di dimensioni variabili). Tuttavia, non è necessario implementare questa indiretta tramite puntatori.
La maggior parte dei linguaggi di programmazione di alto livello (vale a dire non Assembly) sono abbastanza sicuri per la memoria e non consentono l'accesso puntatore senza restrizioni. La famiglia C è quella strana qui.
C si è evoluto da B, che era un'astrazione molto sottile rispetto all'assemblaggio grezzo. B aveva un solo tipo: la parola. La parola potrebbe essere utilizzata come numero intero o come puntatore. Questi due sono equivalenti quando l'intera memoria è vista come un singolo array contiguo. C ha mantenuto questo approccio piuttosto flessibile e ha continuato a supportare l'aritmetica del puntatore intrinsecamente non sicura. L'intero sistema di tipi di C è più un ripensamento. Questa flessibilità di accesso alla memoria ha reso C molto adatto al suo scopo principale: la prototipazione del sistema operativo Unix. Naturalmente Unix e C si sono rivelati piuttosto popolari, quindi C è usato anche in applicazioni in cui questo approccio di basso livello alla memoria non è realmente necessario.
Se osserviamo i linguaggi di programmazione che precedevano C (es. Fortran, dialetti Algol inclusi Pascal, Cobol, Lisp, ...) alcuni di questi supportano i puntatori C-like. In particolare, il concetto di puntatore nullo è stato inventato per Algol W nel 1965. Ma nessuna di quelle lingue ha cercato di essere un linguaggio di sistemi a bassa astrazione di tipo C, efficiente: Fortran era pensato per il calcolo scientifico, Algol ha sviluppato alcuni concetti abbastanza avanzati, Lisp era più di un progetto di ricerca che di un linguaggio di livello industriale, e Cobol si è concentrato sulle applicazioni aziendali.
La raccolta dei rifiuti esisteva dalla fine degli anni '50, vale a dire ben prima di C (primi anni '70). GC richiede che la sicurezza della memoria funzioni correttamente. Le lingue prima e dopo C usavano GC come una caratteristica normale. Ovviamente ciò rende un linguaggio molto più complicato e forse più lento, il che era particolarmente evidente nel tempo dei mainframe. I linguaggi GC tendevano a essere orientati alla ricerca (ad esempio Lisp, Simula, ML) e / o richiedono potenti stazioni di lavoro (ad esempio Smalltalk).
Con i computer più piccoli e potenti, i computer in generale e le lingue GC in particolare sono diventate più popolari. Per applicazioni non in tempo reale (e talvolta anche allora) GC è ora l'approccio preferito. Ma anche gli algoritmi GC sono stati oggetto di intense ricerche. In alternativa, è stata ulteriormente sviluppata una migliore sicurezza della memoria senza GC, soprattutto negli ultimi tre decenni: innovazioni notevoli sono RAII e puntatori intelligenti in C ++ e il sistema di controllo della durata / prestito di Rust.
Java non ha innovato essendo un linguaggio di programmazione sicuro per la memoria: fondamentalmente ha preso la semantica del linguaggio GCted, Smalltalk sicuro per la memoria e li ha combinati con la sintassi e la tipizzazione statica del C ++. È stato quindi commercializzato come C / C ++ migliore e più semplice. Ma è solo superficialmente un discendente del C ++. La mancanza di puntatori di Java è dovuta molto più al modello a oggetti Smalltalk che a un rifiuto del modello di dati C ++.
Quindi i linguaggi "moderni" come Java, Ruby e C # non dovrebbero essere interpretati come il superamento dei problemi di puntatori grezzi come in C, ma dovrebbero essere visti come attingendo da molte tradizioni, tra cui C, ma anche da linguaggi più sicuri come Smalltalk, Simula, o Lisp.