This repository has been archived by the owner on Jun 16, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
274d8dd
commit 413ff20
Showing
5 changed files
with
256 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
# Memoria dinamica | ||
Spesso non si conosce quanti dati memorizzare a tempo di scrittura del programma | ||
=> vogliamo allocare memoria a tempo di esecuzione -> allocazione dinamica della memoria | ||
|
||
Quando lancio un processo il SO riserva al programma una certa quantità di memoria. Questo spazio allocato in modo contiguo è suddiviso in segmenti. | ||
Uno di questi segmenti è chiamato _heap_ (oppure memoria livera o memoria dinamica). All'interno di questo segmento posso allocare memoria in modo arbitrario a tempo di esecuzione, pur rispettando la dimensione fornita dal SO. | ||
|
||
I: l'indirizzo di memoria del primo byte dell'heap è costante durante tutta l'esecuzione del programma | ||
|
||
## Oggetti dinamici | ||
Utilizzeremo array dinamici -> possono cambiare dimensione a tempo di esecuzione. | ||
|
||
In C standard si usa `malloc()` | ||
|
||
In Cpp useremo `new`: | ||
``` | ||
new <nome_tipo> [<num_elementi>]; | ||
``` | ||
<num_elementi> può essere una espressione qualsiasi | ||
W: il vettore sopra dichiarato non ha nome (identificatore) | ||
|
||
`new` alloca solamente un certo spazio in memoria (heap) | ||
|
||
Return value: indirizzo di memoria del primo elemento -> indirizzo dell'area di memoria riservata | ||
|
||
## Puntatore | ||
Dobbiamo memorizzare questo indirizzo in una variabile per poter accedere all'area di memoria allocata mediante un identificatore | ||
|
||
Def: un oggetto di tipo puntatore è una variabile che ha per valore un indirizzo di memria (numero naturale) | ||
|
||
### Dichiarazione | ||
``` | ||
[const] <tipo_oggetto_puntato> * [const] <identificatore> [= <indirizzo>]; | ||
``` | ||
|
||
Il primo _const_ va inserito se il puntatore fa riferimento ad un oggetto non modificabile | ||
Il secondo _const_ va inserito se il valore del puntatore non deve essere modificato dopo l'inizializzazione | ||
|
||
Esempio: allocaizone di un array di N elementi | ||
``` | ||
int *p = new int[N]; | ||
``` | ||
|
||
### Accesso agli elementi | ||
=> identico a quello degli array -> operatore parentesi quadri | ||
|
||
W: non vengono effettuati controlli sulla dimensione e l'accesso in memoria come visto fin'ora | ||
|
||
I: `htop` o `top` per visualizzare l'utilizzo di memoria di un processo | ||
|
||
### Valori, operazioni, tempo di vita | ||
Il puntatore nullo (NULL) è un puntatore che contiene 0 come valore. | ||
|
||
Prevede che le operazioni siano correlate al tipo di dato a cui si punta. | ||
|
||
I puntatori seguono le stesse regole su visibilità e tempo di vita di tutte le altre variabili (ma non l'area di memoria allocata dall'operatore new) | ||
|
||
### Tempo di vita di un array dinamico | ||
Non confondere un puntatore con l'array ad esso associare. | ||
|
||
Una volta allocato un array dinamico esiste fino alla fine del programma (anche quando scompaiono tutti i riferimenti ad esso, compreso il puntatore) oppure fino a che non viene _deallocata_ l'area di memoria. | ||
|
||
### Dealocazione area di memoria | ||
=> per liberare un area di memoria | ||
|
||
``` | ||
delete[] <indirizzo_da_deallocare> | ||
``` | ||
|
||
W: perdendo qualsiasi riferimento ad un array dinamico la memoria non può essere deallocata, quindi rimane occupata ma non utilizzabile fino alla terminazione del procesos | ||
|
||
I: l'operatore `delete` può essere applocato anche al puntatore nullo | ||
|
||
W: un errore di gestione della memoria si verifica quando viene deallocata un'area di memoria mai allocata nell'heap oppure già allocata | ||
|
||
Hint: utilizza sempre il delete alla fine di una funzione/del main per evitare _memory leak_ -> errore difficile da trovare a meno che non si controlli in continuazione la memory footprint del programma. | ||
|
||
### Passaggio per riferimento alle funzioni | ||
``` | ||
[const] <nometipo>< <identificatore> [] | ||
// oppure | ||
[const] <nometipo> * <identificatore> | ||
``` | ||
|
||
Gli array sono sempre passati per riferimento | ||
|
||
Il parametro formale contiene una copia dell'indirizzo dell'array (quindi questo tipo di passaggio è per valore) | ||
|
||
Il nome dell'array è equivalente al nome del primo elemento | ||
|
||
### Ritorno da parte di funzioni | ||
Posso allocare un array dinamico dentro ad una funzione e farmi ritornare il puntatore ad esso, dove sono memorizzati i valori di ritorno. Dovrò ricordarmi di deallocare l'area di memoria allocata nella funzione. | ||
|
||
Alla fine della funzione viene deallocato solo il *puntatore* e non la memoria da esso puntata. | ||
|
||
I: con "dinamico" non si intende che la dimensione dell'array viene conosciuta solamente a tempo di esecuzione del programma, non che è possibile modificarne la dimensione dinamicamente. | ||
|
||
Quando ritorno un vettore ho anche bisogno della sua dimensione. I metodi sono: | ||
- struct con 2 campi | ||
- passo dim per riferimento e ritorno il puntatore al vettore | ||
- passo il puntatore al vettore per riferimento e ritorno la dimensione | ||
|
||
### Riferimento ad un puntatore | ||
``` | ||
[const] <nometipo>* & <identificatore> = <nomeoggetto> | ||
``` | ||
|
||
La variabile così definita è un riferimento a puntatore e può tornare utile per modificare un oggetto di tipo puntatore. | ||
|
||
Esempio: | ||
``` | ||
void creaVett(int* &v, int &num) { ... } | ||
``` | ||
|
||
## Dangling reference | ||
Oppure pending pointer | ||
|
||
Quando si ha un puntatore che punta ad un'area di memoria che non è stata allocata oppure che è stata deallocata. Il comportamento del programma diventa non deterministico (in base alla disposizione e quantità della memoria il programma funziona oppure no) | ||
|
||
## Esaurimento memoria | ||
In assenza di memoria libera disponibile l'operatore new fallisce e viene generata un'eccezione | ||
|
||
### Memory leak | ||
=> problema derivante dalla mancata deallocazione degli oggetti dinamici, che comporta un esaurimento della RAM/swap totale | ||
|
||
Il memory leak può verificarsi anche all'interno di una funzione | ||
|
||
## Tipo di array dinamici | ||
### Strighe dinamiche | ||
``` | ||
char * const str = new char[11]; | ||
``` | ||
|
||
### Array dinamico di strutture | ||
``` | ||
struct persona { ... }; | ||
persona* const t = new persona[dim]; | ||
``` | ||
|
||
### Matrici dinamiche | ||
=> array dinamico di array (statico, anche se in realtà funziona anche con gli array din di array din) | ||
|
||
``` | ||
int (*p) [10] = new int[n][10]; | ||
``` | ||
Passaggio a funzione: | ||
``` | ||
[const] <nometipo> (*<identificatore>) [<espr_costante>]; | ||
``` | ||
### Esercizi | ||
// TODO: percorso_semplificato.cpp | ||
// TODO: percorso.cpp | ||
// TODO: pila.cpp | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#include <iostream> | ||
|
||
using namespace std; | ||
|
||
void crea_copia_array(const int v1[], const int dim, int* &v2) { | ||
v2 = new int[dim]; | ||
for (int i=0; i<dim; i++) | ||
v2[i] = v1[i]; | ||
} | ||
|
||
int main() { | ||
const int N = 3; | ||
int vettore[N] = {10, 20, 30}; | ||
int *dest; | ||
|
||
crea_copia_array(vettore, N, dest); | ||
|
||
for (int i=0; i<N; i++) | ||
cout << dest[i] << " "; | ||
|
||
delete[] dest; | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
#include <iostream> | ||
#include <cstring> | ||
|
||
using namespace std; | ||
|
||
int main() { | ||
int n; // dimensione array dinamico scelta dall'utente | ||
cout << "Dimensione array: "; | ||
cin >> n; | ||
|
||
int *a = new int[n]; // allocazione | ||
|
||
// riempimento | ||
for (int i=0; i<n; i++) { | ||
cout << "Elemento numero "<<i+1<<" : "; | ||
cin >> a[i]; | ||
} | ||
|
||
// stampa | ||
cout << endl << "STAMPA" << endl; | ||
for (int i=0; i<n; i++) { | ||
cout << "Elemento numero "<<i+1<<" : "; | ||
cout << a[i] << endl; | ||
} | ||
|
||
int n2; // nuova dimensione | ||
do { | ||
cout << "Quanti elementi vuoi conservare? "; | ||
cin >> n2; | ||
} while (!(n2>=0 && n2<=n)); | ||
|
||
int *a2 = new int[n2]; | ||
|
||
// copia | ||
memcpy(a2, a, sizeof(int)*n2); | ||
|
||
// deallocazione vecchio array | ||
delete[] a; | ||
|
||
// stampa | ||
cout << endl << "STAMPA" << endl; | ||
for (int i=0; i<n2; i++) { | ||
cout << "Elemento numero "<<i+1<<" : "; | ||
cout << a2[i] << endl; | ||
} | ||
|
||
// deallocazione array nuovo | ||
delete[] a2; | ||
|
||
return 0; | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#include <iostream> | ||
|
||
using namespace std; | ||
|
||
int main() { | ||
int n; | ||
cout << "Dimensione del vettore: "; | ||
cin >> n; | ||
|
||
int *a = new int[n]; | ||
|
||
for (int i=0; i<n; i++) { | ||
cout << "Elemento "<<i+1<<" : "; | ||
cin >> a[i]; | ||
} | ||
|
||
for (int i=0; i<n; i++) { | ||
cout << "Elemento "<<i+1<<" : "; | ||
cout << a[i] << endl; | ||
} | ||
|
||
// Utilizza htop per visualizzare | ||
// l'utilizzo della memoria | ||
|
||
return 0; | ||
} |