Le giovani menti hanno bisogno di imparare i concetti del puntatore?

89

Perché il master C Dennis Ritchie ha introdotto dei puntatori in C? E perché gli altri linguaggi di programmazione come VB.NET o Java o C # li hanno eliminati? Ho trovato alcuni punti su Google e voglio ascoltare anche i tuoi commenti. Perché stanno eliminando i concetti dei puntatori nelle lingue moderne?

La gente dice che C è la lingua di base e i puntatori sono il concetto che rende C potente e eccezionale e rende C ancora competere con i linguaggi più moderni. Allora perché hanno eliminato i puntatori nelle lingue più moderne?

Pensi che la conoscenza dei puntatori sia ancora importante per i nuovi programmatori? Al giorno d'oggi le persone utilizzano VB.NET o Java, che supporta funzioni più avanzate di C (e non utilizza alcun concetto di puntatore) e molte persone come vedo ora (i miei amici) scelgono queste lingue ignorando C poiché supportano funzionalità avanzate. Dico loro di iniziare con C. Dicono che è uno spreco imparare i concetti dei puntatori quando stai facendo le cose avanzate in VB.NET o Java che non sono possibili in C.

Che ne pensi?

Aggiornamento :

I commenti che ho letto su Google sono:

  1. I computer precedenti erano troppo lenti e non ottimizzati.

  2. L'uso dei puntatori consente di accedere direttamente a un indirizzo e questo consente di risparmiare tempo invece di crearne una copia nelle chiamate di funzione.

  3. La sicurezza è significativamente peggiore usando i puntatori, ed è per questo che Java e C # non li hanno inclusi.

Questi e altri ancora quello che ho trovato. Ho ancora bisogno di alcune risposte preziose. Sarebbe molto apprezzato.

    
posta niko 05.09.2011 - 22:50
fonte

16 risposte

127

In quei giorni, gli sviluppatori lavoravano molto più vicino al metallo. C era essenzialmente un rimpiazzo di livello superiore per l'assemblaggio, che è quasi il più vicino possibile all'hardware, quindi era naturale che avessimo bisogno di indicatori per essere efficienti nel risolvere i problemi di codifica. Tuttavia, i puntatori sono strumenti appuntiti, che possono causare gravi danni se usati con noncuranza. Inoltre, l'uso diretto dei puntatori apre la possibilità a molti problemi di sicurezza, che non erano un problema allora (nel 1970, Internet era costituito da circa una dozzina di macchine in un paio di università, e non era nemmeno chiamato così ...), ma da allora è diventato sempre più importante. Quindi oggigiorno linguaggi di livello superiore sono progettati in modo consapevole per evitare i puntatori di memoria grezza.

Dicendo che "le cose avanzate fatte in VB.Net o Java non sono possibili in C" mostra un punto di vista molto limitato, per usare un eufemismo: -)

Prima di tutto, tutti questi linguaggi (anche l'assemblaggio) sono completati da Turing, quindi in teoria tutto ciò che è possibile in una lingua è possibile in tutti. Pensa solo a cosa succede quando un pezzo di codice VB.Net o Java viene compilato ed eseguito: alla fine, viene tradotto in (o mappato a) codice macchina, perché questa è l'unica cosa che la macchina capisce. In linguaggi compilati come C e C ++, è possibile ottenere l'intero codice macchina equivalente al codice sorgente di livello superiore originale, come uno o più file eseguibili / librerie. Nei linguaggi basati su VM, è più complicato (e potrebbe anche non essere possibile) ottenere l'intera rappresentazione del codice macchina equivalente del tuo programma, ma alla fine è ancora lì da qualche parte, nei recessi profondi del sistema di runtime e del JIT.

Ora, naturalmente, è una domanda completamente diversa se una soluzione sia fattibile in una lingua specifica. Nessuno sviluppatore ragionevole avrebbe iniziato a scrivere un'app Web in assemblaggio :-) Ma è utile ricordare che la maggior parte o tutti quei linguaggi di livello superiore sono basati su un'enorme quantità di codice di libreria di runtime e classe, una grande porzione di che è implementato in un linguaggio di livello inferiore, tipicamente in C.

Quindi, per ottenere la domanda,

Do you think knowledge on pointers to the young people [...] is important?

Il concetto dietro i puntatori è indiretto . Questo è un concetto molto importante e IMHO ogni buon programmatore dovrebbe coglierlo ad un certo livello. Anche se qualcuno sta lavorando esclusivamente con linguaggi di livello superiore, l'indirezione e i riferimenti sono ancora importanti. Non comprenderlo significa non essere in grado di utilizzare un'intera classe di strumenti molto potenti, limitando seriamente la capacità di problem solving a lungo termine.

Quindi la mia risposta è sì, se vuoi diventare un vero programmatore, devi capire anche i puntatori (oltre alla ricorsione - questo è l'altro tipico ostacolo per gli sviluppatori in erba). Potrebbe non essere necessario iniziare con esso - non credo che C sia ottimale come prima lingua al giorno d'oggi. Ma a un certo punto si dovrebbe acquisire familiarità con l'indirezione. Senza di esso, non potremo mai capire come funzionano effettivamente gli strumenti, le librerie e i framework che stiamo utilizzando. E un artigiano che non capisce come funzionano i suoi strumenti è molto limitato. Abbastanza corretto, si può averne una conoscenza anche in linguaggi di programmazione di livello superiore. Una buona cartina al tornasole sta implementando correttamente una lista doppiamente collegata: se riesci a farlo nella tua lingua preferita, puoi affermare di aver compreso bene l'induzione indiretta.

Ma se non altro, dovremmo farlo per imparare il rispetto per i programmatori di vecchi che sono riusciti a costruire cose incredibili usando gli strumenti ridicolmente semplici che avevano (rispetto a quello che abbiamo ora). Siamo tutti sulle spalle dei giganti, e fa bene a noi riconoscerlo, piuttosto che fingere di essere noi stessi i giganti.

    
risposta data 05.09.2011 - 12:29
fonte
38

Penso che tu debba essere diverso.

Java e altri linguaggi di livello superiore non rimuovevano i puntatori. Quello che hanno fatto è stato rimuovere la semplice aritmetica dei puntatori.

Infatti, Java consente ancora un aritmetico del puntatore protetto e limitato : l'accesso all'array. Nella semplice vecchia C, l'accesso agli array non è altro che il dereferenziazione. È una notazione diversa, uno zucchero sintattico, se vuoi, per comunicare chiaramente, cosa stai facendo.
Tuttavia, array[index] equivale a *(array+index) . Per questo è anche equivalente a index[array] anche se suppongo che alcuni compilatori C potrebbero darti un avvertimento, se lo fai.
Come corollario, pointer[0] equivale a *pointer . Questo è semplicemente perché il "puntatore a un array" è l'indirizzo della prima voce dell'array e gli indirizzi degli elementi successivi sono calcolati aggiungendo l'indice.

In Java, l'aritmetica puntatore semplice (referenziamento e dereferenziazione) non esiste più. Tuttavia esistono dei puntatori. Li chiamano riferimenti, ma non cambia quello che è. E l'accesso all'array è ancora esattamente la stessa cosa: guarda l'indirizzo, aggiungi l'indice e usa quella posizione di memoria. Tuttavia, in Java, controllerà se tale indice si trova entro i limiti dell'array originariamente assegnato. In caso contrario, genererà un'eccezione.

Ora il vantaggio dell'approccio Java è che non hai codice, che scrive ciecamente byte arbitrari in posizioni di memoria arbitrarie. Ciò migliora la sicurezza e anche la sicurezza, perché se non riesci a controllare i buffer overflow e così via, il runtime lo farà per te.

Lo svantaggio di questo è che è semplicemente meno potente. È possibile fare una programmazione sicura della memoria in C. È impossibile beneficiare della velocità e delle possibilità di programmazione non sicura in Java.

In realtà, non c'è nulla di difficile nei puntatori o nell'aritmetica dei puntatori. Solitamente vengono spiegati in modi convoluti, mentre tutto un puntatore è, è un indice di un gigantesco array (lo spazio di memoria), tutto ciò che fa riferimento a un valore è fornire l'indice dove trovarlo, tutto ciò che la dereferenziazione fa è cercare il valore in un dato indice. (Questo è solo un po 'semplificato, perché non tiene conto del fatto che i valori sono di dimensioni diverse in memoria, a seconda del loro tipo. Ma questo è un dettaglio circostanziale, piuttosto che una parte del concetto reale)

IMHO, tutti nel nostro lavoro dovrebbero essere in grado di capirlo, o sono semplicemente nel campo sbagliato.

    
risposta data 05.09.2011 - 13:08
fonte
24

Il concetto di puntatori è importante nel corpo di conoscenza generale della programmazione per computer. Comprendere il concetto è buono per i programmatori o programmatori di qualsiasi lingua, anche se la lingua non lo supporta direttamente.

I puntatori hanno il loro utilizzo in strutture dati (elenchi concatenati) e progettazione di database (chiave esterna).

Lingue come VB e C # possono passare i dati per "riferimento" ai metodi, che possono essere considerati come un tipo di puntatore.

Capire dove i dati sono allocati in memoria (stack contro heap) è ancora importante per l'efficienza degli algoritmi.

L'apprendimento delle basi è importante, a mio parere.

    
risposta data 05.09.2011 - 11:42
fonte
19

Sì, sì, sì, sì e sì !!!

Se non conosci le basi, non sarai MAI in grado di risolvere i problemi veramente difficili, strani, difficili e complicati che ti capitano.

E se capisci molto bene le basi, sei molto più commerciabile nel mercato del lavoro.

Ho lavorato una volta con un tizio che aveva programmato per 10 anni e non avevo idea di come funzionassero i puntatori. Io (molto più giovane) ho passato ore a una lavagna per educarlo. Questo ha aperto i miei occhi. Non aveva IDEA su così tante cose di base.

Conosci il più possibile.

    
risposta data 05.09.2011 - 12:54
fonte
17

Sì, la comprensione è importante.

Alcuni mesi fa stavo programmando in C # e volevo fare una copia di una lista. Ovviamente quello che ho fatto è stato NewList = OldList; e poi ho iniziato a modificare NewList . Quando ho provato a stampare entrambi gli elenchi, erano entrambi uguali, poiché NewList era solo un puntatore a OldList e non una copia, quindi in realtà stavo cambiando OldList per tutto il tempo. Non mi ci è voluto molto tempo per capirlo, ma alcuni dei miei compagni di classe non erano così veloci e hanno dovuto spiegare perché questo sta accadendo.

Esempio:

List<int> a = new List<int>();
a.Add(2);
a.Add(9);
a.Add(8);
a.Add(1);
List<int> b = new List<int>();
b = a; //Does not make a copy, b is just a synonym!
b.Sort();
for (int i = 0; i < a.Count; i++)
{
    Console.WriteLine("a: " + a[i] + " b: " + b[i]);
}

E, naturalmente, il risultato è il seguente:

a: 1 b: 1
a: 2 b: 2
a: 8 b: 8
a: 9 b: 9

Sapere come usarli non è così importante, tuttavia comprenderli è fondamentale!

    
risposta data 05.09.2011 - 23:06
fonte
14

Puntare il concetto! = Puntare l'aritmetica! = Puntare la sintassi

Il primo è sempre importante, se hai bisogno (e lo fai) di comprendere la copia profonda / superficiale, passare per riferimento / passare per valore, ecc. Gli altri due sono importanti solo se il tuo linguaggio du jour ti permette di usarli.

    
risposta data 05.09.2011 - 15:25
fonte
14

Why did the C master Dennis Ritchie introduce pointers in C?

Perché i puntatori sono un meccanismo molto potente che può essere utilizzato in molti modi.

And why did the other programming languages like VB.NET or Java or C# eliminate them?

Perché i puntatori sono un meccanismo molto pericoloso che può essere usato impropriamente in molti modi.

Penso che i programmatori dovrebbero conoscere i puntatori, ma dal punto di vista educativo, non è saggio introdurli in anticipo. La ragione è che sono usati per tanti scopi diversi, è difficile dire come principianti perché stai usando un puntatore in una circostanza particolare.

Ecco un elenco incompleto su quali puntatori vengono usati:

  • allocazione dinamica ( new T )
  • strutture dati ricorsive ( struct T { T* next; /* ... */ }; )
  • iteratori su array ( for (T* p = &a[0]; p != &a[0] + n; ++p) { ... } )
  • accesso condiviso agli oggetti ( T* new_pointer = existing_pointer; )
  • polimorfismo del sottotipo ( T* pointer_to_base = pointer_to_derived; )
  • chiamata precedente per riferimento ( mutate(&object); )
  • tipi facoltativi ( if (p) { /* ... */ } )

Si noti che l'utilizzo di un singolo meccanismo per tutti questi concetti dimostra sia la potenza che l'eleganza per il programmatore esperto e il grande potenziale di confusione per chi è nuovo alla programmazione.

    
risposta data 05.09.2011 - 23:06
fonte
12

Perché? Puoi scrivere un enorme sistema con form designer e generatore di codice. Non è sufficiente? (Ironia)

E ora sul serio, i puntatori non sono una parte cruciale della programmazione in molte aree, ma permettono alle persone di capire come funzionano gli interni. E se non avessimo nessuno che capisca come funzionano gli interni, ci sarà una situazione in cui SQL2020, Windows 15 e Linux 20.04 saranno scritti in una macchina virtuale raccolta in spazzatura su oltre 30 livelli di astrazione, con codice generato tramite IDE, in JavaScript .

Questo non è sicuramente quello che voglio vedere.

Quindi sì, devono farlo, sicuramente!

    
risposta data 05.09.2011 - 12:12
fonte
7

Né Java né C # eliminano i puntatori, hanno riferimenti quasi identici. Ciò che è stato eliminato è l'aritmetica puntatore, che può essere omessa in un corso introduttivo.
Nessuna applicazione non banale può essere eseguita senza il concetto di puntatori o riferimenti, quindi vale la pena di insegnare (non è possibile eseguire alcuna allocazione della memoria dinamica senza di essi).

Considera quanto segue in C ++ e Java, e immagino che non sia molto diverso in C #:
aClass *x = new aClass();
aClass x = new aClass();
Non c'è davvero troppa differenza tra puntatori e riferimenti, giusto?
L'aritmetica del puntatore dovrebbe essere evitata a meno che non sia necessario e quando si programma con i modelli di alto livello, quindi non c'è molto problema lì.

    
risposta data 05.09.2011 - 15:41
fonte
6

Il programmatore professionista dovrebbe padroneggiare i puntatori.

Le persone che vogliono conoscere la programmazione dovrebbero conoscere la sua esistenza e le sue implicazioni, ma non necessariamente usarle.

Le persone che vogliono risolvere problemi personali tramite programmazione (come me, che usano molti script Python) potrebbero benissimo ignorarle del tutto.

Bene, questa è la mia opinione ...; o)

    
risposta data 05.09.2011 - 15:03
fonte
3

I puntatori agli indirizzi variabili sono un caso specifico del concetto più generalizzato di indirezione. L'indirizzamento è utilizzato nella maggior parte (tutti?) Dei linguaggi moderni in molti costrutti come delegati e callback. Comprendere il concetto di indirezione ti consente di sapere quando e come utilizzare al meglio questi strumenti.

    
risposta data 05.09.2011 - 15:17
fonte
3

Absufreakinglutely YES ! Chiunque programmi abbia bisogno di capire i puntatori e l'indirezione.

I puntatori indicano come viene eseguita una grande quantità di accesso ai dati in tutte le lingue. I puntatori sono una caratteristica hardware di tutti i microprocessori. Lingue di alto livello come Java, VB e amp; C # essenzialmente elimina l'accesso diretto ai puntatori dagli utenti della lingua con riferimenti. I riferimenti fanno riferimento agli oggetti tramite lo schema di gestione della memoria del linguaggio (potrebbe essere un puntatore con metadati o solo un numero per una tabella di memoria, ad esempio).

Capire come funzionano i puntatori è fondamentale per capire come funzionano effettivamente i computer. I puntatori sono anche più flessibili e potenti dei riferimenti.

Ad esempio, il motivo per cui gli array iniziano con l'indice zero è perché gli array sono in realtà una scorciatoia per l'aritmetica del puntatore. Senza sapere come funzionano i puntatori, molti programmatori principianti non ottengono abbastanza array.

int a, foo[10];
foo[2] = a;

La linea 2 nell'aritmetica del puntatore sarebbe:

*(foo + sizeof(int) * 2) = a;

Senza capire i puntatori, non si può capire la gestione della memoria, lo stack, l'heap o persino gli array! Inoltre, è necessario comprendere i puntatori e il dereferenziamento per capire come vengono passate le funzioni e gli oggetti.

TL: DR : la comprensione dei puntatori è fondamentale per comprendere i computer in realtà funzionano .

    
risposta data 06.09.2011 - 10:02
fonte
2

Penso che si riducano al fatto che la necessità di gestire i puntatori è diminuita poiché i programmatori si sono occupati meno dell'hardware diretto su cui stavano lavorando. Ad esempio, allocare una struttura di dati dell'elenco collegato in un modo che si adatti perfettamente alla sequenza di moduli di memoria 640 byte che l'hardware specializzato aveva.

Gestire manualmente i puntatori può essere soggetto a errori (che porta a perdite di memoria e codice sfruttabile) e richiede tempo per essere corretto. Quindi Java e C # etc ora gestiscono la tua memoria e i tuoi indicatori per te tramite le loro macchine virtuali (VM). Questo è probabilmente meno efficiente rispetto all'utilizzo di C / C ++ non elaborato, sebbene le macchine virtuali siano in costante miglioramento.

C (e C ++) sono ancora lingue ampiamente utilizzate, specialmente negli spazi di calcolo ad alte prestazioni, giochi e hardware embedded. Personalmente sono grato di aver imparato a proposito dei puntatori come la transizione ai riferimenti di Java (un concetto simile ai puntatori) è stata molto semplice e non mi sono perso quando ho visto la mia prima NullPointerException (che dovrebbe essere chiamata NullReferenceException, ma divago) .

Consiglierei di conoscere il concetto di puntatori perché sono ancora alla base di molte strutture di dati, ecc. Poi continuiamo a scegliere una lingua che ti piace lavorare, sapendo che se qualcosa come un NPE viene fuori, sai cosa è davvero andando avanti.

    
risposta data 05.09.2011 - 11:45
fonte
0

Questa è la verità oggettiva:

Alcune lingue supportano l'accesso diretto alla memoria (puntatori), altre no. Ci sono buone ragioni per ogni caso.

  1. Come qualcuno ha detto qui, ai tempi di C, la gestione automatica della memoria non era così elaborata come oggi. E le persone erano state abituate, comunque. I bravi programmatori di allora avevano una comprensione molto più profonda dei programmi per computer rispetto alla nostra generazione (ho 21 anni). Stanno usando schede perforate e giorni di attesa per un po 'di compilazione sul mainframe. Probabilmente sapevano perché ogni bit del loro codice esisteva.

  2. L'ovvio vantaggio di linguaggi come C è che ti permettono di avere un controllo più preciso sul tuo programma. Quando in realtà hai bisogno di , in questi giorni? Solo quando si creano applicazioni infrastrutturali, come programmi relativi al sistema operativo e ambienti di runtime. Se vuoi solo sviluppare un software buono, veloce, robusto e affidabile, la gestione automatica della memoria è molto spesso la scelta migliore.

  3. Il fatto è che l'accesso diretto alla memoria è stato per lo più abusato nel corso della storia dello sviluppo del software. Le persone avevano creato programmi che perdevano memoria, e in realtà erano più lenti a causa dell'allocazione di memoria ridondante (in C è facile e comune estendere lo spazio di memoria virtuale del processo per ogni singola allocazione).

  4. Oggigiorno, le macchine virtuali / i runtime eseguono un lavoro molto migliore del 99% dei programmatori nell'allocare e rilasciare la memoria. Inoltre, ti permettono una maggiore flessibilità nel flusso che vuoi che il tuo programma abbia, perché non sei (per lo più) occupato a liberare memoria allocata al momento e nel luogo giusto.

  5. Per quanto riguarda la conoscenza. Penso sia ammirevole che i programmatori sappiano come vengono implementati gli ambienti in cui vengono programmati. Non necessariamente per i più piccoli dettagli, ma per il quadro generale.

Penso che sapere come funzionano i puntatori (per lo meno) è interessante. Come sapere come viene implementato il polimorfismo. Da dove proviene il tuo processo e come. Queste sono cose che mi sono sempre state di interesse, personalmente. Posso dire onestamente che mi hanno reso un programmatore migliore, ma non posso dire che siano una necessità educativa per chiunque voglia diventare un buon programmatore. In entrambi i casi, sapere di più spesso ti renderà migliore nel tuo lavoro.

  1. Per come la vedo io, se tutto ciò che ti viene chiesto è creare un'applicazione in Java o C # o qualcosa di simile, devi concentrarti su una corretta progettazione e tecniche di implementazione. Codice verificabile, codice pulito, codice flessibile. In questo ordine.

Perché anche se non conosci tutti i piccoli dettagli, chi lo fa sarà in grado di cambiare ciò che avrai creato in qualcosa che semplicemente si comporta meglio. E questo spesso non è un lavoro difficile, una volta che hai un progetto corretto, pulito e verificabile (e di solito è la maggior parte del lavoro).

Se fossi un intervistatore che cercasse di assumere qualcuno per un'applicazione linguistica di alto livello, quelle sarebbero le cose a cui sarei più interessato.

La conoscenza di basso livello è un bonus. È utile per eseguire il debug e talvolta creare soluzioni leggermente migliori. Ti rende una persona interessante, professionalmente. Ti garantisce un po 'di rispetto sul posto di lavoro.

Ma nel mondo di oggi, non è un requisito sacro.

    
risposta data 11.09.2011 - 20:52
fonte
-1

Per la maggior parte degli scopi pratici nei linguaggi OO di alto livello, la comprensione dei riferimenti è sufficiente, non è davvero necessario capire in che modo questi linguaggi implementano i riferimenti in termini di puntatori.

Esistono molti più approcci multi-paradigma funzionali e moderni Valorizzerei molto di più che essere in grado di fare aritmetica puntata di fantasia per dire, scrivere la millesima funzione ottimizzata di copiatura delle stringhe probabilmente con risultati peggiori di String.copy della tua lib di std in qualsiasi modo.

Consiglierei di imparare molti più concetti di livello superiore prima di iniziare a imparare lingue di diversi design per ampliare il tuo orizzonte prima di tentare di specializzarti in cose da vicino.

Spesso vedo tentativi totalmente falliti di ottimizzare micro-Web servlet o codice simile per ottenere un guadagno del 5%, quando la configurazione della cache (memoization), l'ottimizzazione SQL o semplicemente la configurazione del server web possono produrre il 100% o più con poco sforzo. Lottare con i puntatori è ottimizzazione prematura nella maggior parte dei casi.

    
risposta data 05.09.2011 - 12:35
fonte
-1

Sicuramente, dobbiamo avere un concetto completo di puntatore, se vuoi davvero essere un buon programmatore. Il motivo del concetto di puntatore era un accesso diretto al tuo valore che diventa più efficiente ed efficace con limiti di tempo ...

Inoltre, ora un giorno, considerando le applicazioni mobili, che hanno una memoria molto limitata, dobbiamo usarlo molto attentamente in modo che il suo funzionamento sia molto veloce con la risposta degli utenti ... Quindi per questo scopo abbiamo bisogno di un riferimento diretto al valore ...

Considera i dispositivi Apple, o il linguaggio Objective C, che funziona esclusivamente con il concetto di puntatore. Tutta la variabile dichiarata nell'Obiettivo C sta avendo Pointer. Devi passare attraverso wiki dell'obiettivo C

    
risposta data 11.09.2011 - 19:06
fonte

Leggi altre domande sui tag