Per i programmi complessi è necessaria una sorta di indiretta (ad esempio strutture dati ricorsive o di dimensioni variabili). Tuttavia, non è necessario implementare questa indiretta tramite puntatori.
La maggior parte dei linguaggi di programmazione di alto livello (ad esempio, non Assembly) è abbastanza sicura per la memoria e non consente l'accesso senza restrizioni al puntatore. La famiglia C è la 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 usata come un intero o come puntatore. Questi due sono equivalenti quando l'intera memoria è vista come una singola matrice contigua. C ha mantenuto questo approccio piuttosto flessibile e ha continuato a supportare aritmetica del puntatore intrinsecamente non sicura. L'intero sistema di tipi di C è più di un ripensamento. Questa flessibilità all'accesso alla memoria ha reso C molto adatto allo scopo principale: la prototipazione del sistema operativo Unix. Ovviamente Unix e C si sono rivelati molto popolari, quindi anche C viene utilizzato in applicazioni in cui questo approccio alla memoria di basso livello non è realmente necessario.
Se guardiamo ai linguaggi di programmazione precedenti a C (ad esempio, Fortran, dialoghi di Algol inclusi Pascal, Cobol, Lisp, ...) alcuni di questi supportano i puntatori a forma di C. In particolare, il concetto di puntatore nullo è stato inventato per Algol W nel 1965. Ma nessuno di questi linguaggi ha cercato di essere un linguaggio di sistemi a basso livello di astrazione efficiente e C: Fortran era pensato per il calcolo scientifico, Algol ha sviluppato alcuni concetti abbastanza avanzati, Lisp era più di un progetto di ricerca che un linguaggio di livello industriale, e Cobol era focalizzato 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 hanno utilizzato il GC come caratteristica normale. Ovviamente questo rende la lingua molto più complicata e forse più lenta, cosa particolarmente evidente al tempo dei mainframe. I linguaggi GC tendevano ad essere orientati alla ricerca (ad es. Lisp, Simula, ML) e / o richiedono potenti workstation (ad esempio Smalltalk).
Con computer più piccoli e potenti il computing in generale e i linguaggi GC sono diventati più popolari. Per le applicazioni non in tempo reale (e talvolta anche in quel momento) GC è ora l'approccio preferito. Ma gli algoritmi GC sono stati anche oggetto di intense ricerche. In alternativa, è stata ulteriormente sviluppata una migliore sicurezza della memoria senza GC, specialmente negli ultimi trent'anni: innovazioni notevoli sono RAII e puntatori intelligenti in C ++ e nel sistema di controllo del prestito / prestito a vita di Rust
.
Java non ha innovato essendo un linguaggio di programmazione sicuro per la memoria: praticamente ha preso la semantica del linguaggio GCed, Smalltalk sicuro per la memoria e combinato con la sintassi e la tipizzazione statica del C ++. È stato poi commercializzato come un C / C ++ migliore e più semplice. Ma è solo superficialmente un discendente di C ++. La mancanza di puntatori di Java è dovuta molto più al modello di oggetti Smalltalk che a un rifiuto del modello di dati C ++.
Quindi linguaggi "moderni" come Java, Ruby e C # non dovrebbero essere interpretati come superamento dei problemi dei puntatori grezzi come in C, ma dovrebbero essere visti come attingendo da molte tradizioni - inclusa C, ma anche da linguaggi più sicuri come Smalltalk , Simula o Lisp.