Ci sono diverse difficoltà con i puntatori:
-
Aliasing La possibilità di modificare il valore di un oggetto utilizzando nomi / variabili diversi.
-
Non-località La possibilità di modificare un valore di oggetti in un contesto diverso da quello in cui è dichiarato (questo accade anche con argomenti passati per riferimento).
-
Mancata corrispondenza a vita La durata di un puntatore può essere diversa dalla durata dell'oggetto a cui punta e ciò può portare a riferimenti non validi (SEGFAULTS) o garbage.
-
Aritmetica puntatore . Alcuni linguaggi di programmazione consentono la manipolazione di puntatori come numeri interi e ciò significa che i puntatori possono puntare ovunque (compresi i punti più inattesi quando è presente un bug). Per usare correttamente l'aritmetica del puntatore, un programmatore deve essere consapevole delle dimensioni della memoria degli oggetti puntati, e questo è qualcosa su cui riflettere.
-
Tipi di cast La possibilità di trasmettere un puntatore da un tipo all'altro consente di sovrascrivere la memoria di un oggetto diverso da quello desiderato.
Ecco perché un programmatore deve pensare in modo più approfondito quando usa i puntatori (non conosco i due livelli di astrazione ). Questo è un esempio degli errori tipici compiuti da un novizio:
Pair* make_pair(int a, int b)
{
Pair p;
p.a = a;
p.b = b;
return &p;
}
Si noti che il codice come sopra è perfettamente ragionevole in linguaggi che non hanno un concetto di puntatori ma piuttosto uno di nomi (riferimenti), oggetti e valori, come linguaggi di programmazione funzionale e lingue con garbage collection (Java, Python).
La difficoltà con le funzioni ricorsive si verifica quando le persone senza sufficiente background matematico (dove la ricorsività è comune e richiede conoscenza) cercano di avvicinarle pensando che la funzione si comporterà in modo diverso a seconda di quante volte è stata chiamata prima . Questo problema è aggravato dal fatto che le funzioni ricorsive possono infatti essere create in modi in cui devi pensare in questo modo per capirle.
Pensa alle funzioni ricorsive con i puntatori che vengono passati in giro, come in un'implementazione procedurale di un Albero rosso-nero in cui la struttura dei dati è modificata sul posto; è qualcosa di più difficile da pensare rispetto a una controparte funzionale .
Non è menzionato nella domanda, ma l'altro problema importante con cui i principianti hanno difficoltà è concorrenza .
Come altri hanno accennato, c'è un problema aggiuntivo, non concettuale, con alcuni costrutti del linguaggio di programmazione: è che anche se comprendiamo, errori semplici e onesti con questi costrutti possono essere estremamente difficili da eseguire il debug.