Differences

This shows you the differences between two versions of the page.

Link to this comparison view

appunti3s:pointers [2018/04/25 07:55] (current)
Line 1: Line 1:
 +====== Puntatori a... (qualcosa) ======
 +=====Memoria automatica=====
 +Le variabili automatiche (cosiddette locali) sono gestite automaticamente nello //stack// e quando non servono più vengono automaticamente "​distrutte"​.
 +=====Memoria dinamica=====
 +vedere [[appunti3s:​code_data_bss]]
 +
 +Durante l'​esecuzione del programma può essere necessario allocare (riservare) dinamicamente della memoria. Questo accade per le operazioni dove non si possono prevedere in anticipo le richieste di un utente. ​
 +Per riservare una zona di memoria dinamicamente si usa l'​operatore //new//.
 +<​code>​new float; // riserva la quantità di memoria necessaria per un numero in virgola mobile</​code>​
 +L'​operatore //new// restituisce l'​indirizzo iniziale della memoria riservata.
 +Quale tipo di dato è utile per memorizzare un indirizzo di memoria? Anche se un indirizzo di memoria è un numero, non si usa il tipo //int//, ma un tipo specifico chiamato //puntatore a...//. Nel precedente esempio si deve usare un "​puntatore a float"​. Per la sua dichiarazione basta aggiungere l'​operatore asterisco * dopo il nome del tipo:
 +<​code>​
 +float* numero; ​      //​definizione della variabile puntatore a...
 +numero = new float; ​ // inizializzazione della variabile puntatore a..
 +</​code>​
 +
 +{{:​appunti3s:​puntatore1.png?​|}}
 +
 +Nel precedente esempio il programma ha riservato due aree di memoria:
 +  * "​numero"​ come variabile //​automatica//,​ per contenere un indirizzo
 +  * "new float" come variabile //​dinamica//,​ per contenere un numero in virgola mobile
 +Le due operazioni possono essere eseguite anche in un solo colpo:
 +<​code>​float* numero = new float;</​code>​
 +La seconda variabile (nell'​heap) sarebbe inutilizzabile senza la prima (nello stack), ma chi è che controlla la "​distruzione"​ della prima? Poiché "​numero"​ è una variabile automatica essa si libera automaticamente quando termina la funzione che la contiene, quindi l'area allocata dinamicamente potrebbe diventare inutilizzabile nel caso in cui questo accadesse. Nell'​esempio visto, il programmatore deve usare //delete// prima che si verifichi questo evento "​disastroso":​
 +
 +<​code>​delete numero;</​code>​
 +
 +Riassumendo,​ questo è l'​ordine in cui si devono fare le cose
 +  * inizia la funzione
 +    - definire un puntatore (nella mem. automatica)
 +    - riservare la memoria dinamica con //new// e inizializzare il puntatore
 +    - utilizzare a proprio piacere l'area dinamica...
 +    - liberare la memoria dinamica con //delete//
 +  * termina la funzione (si libera anche il puntatore)
 +Oppure, in altre parole, ricordarsi di liberare tutte le variabili dinamiche create per evitare problemi di gestione della memoria o falle (memory leak).
 +I puntatori quindi sono variabili usate prevalentemente per controllare la memoria dinamica (//heap//).
 +
 +====Un consiglio====
 +L'​utilizzo dei puntatori è un comune causa di errori o bug nei programmi, soprattutto se questi sono utilizzati per un lungo tempo. La strategia consigliata è di usare l'​operatore //new// solo nei costruttori e l'​operatore //delete// solo nei distruttori.
 +
 +I puntatori e gli array lavorano sulla memoria a basso livello, cioè senza controlli, causando oscuri malfunzionamenti e bug! I vector invece hanno un'​efficenza ancora sufficientemente elevata e sono più facili da usare (ci sono più controlli).
 +
 +Creando un vector (o uno fstream) come oggetto locale, la distruzione sarà eseguita automaticamente al termine della funzione e così si posso evitare i puntatori.
 +In ogni caso, non usare direttamente new e delete, ma creare oggetti con new nel costruttore e delete nel distruttore.
 +
 +===== Perché usare la memoria dinamica? =====
 +
 +La memoria dinamica, rispetto alla memoria automatica, può essere utile per contenere oggetti molto grandi o di dimensioni non note a priori, oppure per contenere oggetti che devono durare a lungo (più della durata degli oggetti locali (automatici) di una funzione).
 +===== Perché usare i puntatori? =====
 +I puntatori non vengono usati solo per accedere alla memoria heap.
 +A volte i puntatori permettono di accedere anche a zone della memoria (stack) altrimenti inaccessibili,​ come quando si vuole che una funzione conosca l'​indirizzo di una variabile usata da un'​altra per poterla modificare. Ma questo utilizzo non dovrebbe essere necessario e probabilmente si basa su un cattivo stile di programmazione.
 +A volte i puntatori permettono di puntare alle funzioni, consentendo di eseguire funzioni diverse per condizioni diverse che si possono verificare in tempo di esecuzione (running time), in altre parole i puntatori consentono anche il [[appunti3s:​polimorfismo]]. ​
 +http://​www.illuminamente.org/​dokuwiki/​doku.php?​id=appunti3s:​stream#​file
 +
 +===== Differenze tra puntatori e array =====
 +<​code>​int a1[5];</​code>​
 +In linguaggio C scrivere "​a1"​ equivale a scrivere l'​indirizzo del primo elemento dell'​array "&​a1[0]"​ , quindi, quando si passa un array ad una funzione, in realtà si passa sempre il valore del suo indirizzo (come un puntatore). ​
 +
 +La differenza tra un puntatore (int p) è l'​indirizzo (&​a1[0]) è che il primo può cambiare e puntare qualsiasi area di memoria, mentre l'​indirizzo del primo elemento di un array non può essere cambiato.
 +===== Similitudini tra puntatori e array =====
 +<​code>​int *p = a1</​code>​
 +Se il puntatore punta all'​area di memoria di un array, si può utilizzare una sintassi simile a quella di un array:
 +<​code>​p[0]=3;​ </​code>​
 +
 +Nelle dichiarazioni delle funzioni si può usare equivalentemente una qualsiasidelle seguenti due sintassi:​rif.standard ​ 13.1-3.3
 +<​code>​int fun(int p[]);
 +int fun(int *p);</​code>​
 +
 +===== Puntatore appeso =====
 +differenza tra 
 +
 +<​code>​
 +return &​variabile;​ // (dangling pointer) resituisce l'​indirizzo di una 
 +                   // var che si autodistrugge(locale,​automatica)</​code>​
 +<​code>​
 +return puntatore; // restituisce un indirizzo (la copia del contenuto di 
 +                  // un puntatore) che contiene l'​indirizzo di (si spera) ​
 +                  // un'​area allocata con new, che sopravvive alla funzione.</​code>​
 +
 +===== Puntatore a void=====
 +È introdotto nel linguaggio C++ per necessità. ​
 +Ovviamente non esistono oggetti //void//. Il tipo //void// viene usato solo per indicare "​nessun valore restituito"​ da una funzione.
 +
 +Il puntatore //void*// è usato solo per poter puntare qualsiasi cosa, che il programma non sa cosa sia (mentre il programmatore deve sapere cosa e').
 +Il tipo //void*// serve solo per copiare un indirizzo di memoria a basso livello e non consente di lavorare sul contenuto della memoria.
 +
 +Questo significa che per poter lavorare sul contenuto bisogna effettuare un casting verso un altro tipo di puntatore. Mentre il casting tra altri tipi può essere implicito, per i puntatori è necessario usare il casting esplicito... ​
 +Mentre esistono conversioni implicite tra float e int, non esiste tra float* e int*
 +
  
  • appunti3s/pointers.txt
  • Last modified: 2018/04/25 07:55
  • (external edit)