Slide dall'Università sui Fondamenti 2024-2025: Allocazione dinamica della memoria in C++. Il Pdf esplora l'allocazione dinamica della memoria in C++, contrapponendola a quella statica, con esempi pratici di riallocazione di array e gestione di strutture dati, utile per Informatica.
Mostra di più21 pagine


Visualizza gratis il Pdf completo
Registrati per accedere all’intero documento e trasformarlo con l’AI.
Fondamenti 2024-2025 - Secondo semestre 17/03/2025 Allocazione dinamica
158
159 1Fondamenti 2024-2025 - Secondo semestre 17/03/2025 Allocazione dinamica
160
Allocazione dinamica Stack Indirizzi di memoria "alti" … Heap Data segment L'organizzazione della memoria dipende dal computer e dal sistema operativo. Solitamente, gli indirizzi dello stack decrescono, mentre gli indirizzi dell'heap crescono Code segment Indirizzi di memoria "bassi" 161 2Fondamenti 2024-2025 - Secondo semestre 17/03/2025
int a=0; int b=0; float f=0; Esperimento 1 int main() { int c=0; int d=0; float g=0; cout << "variabili globali" << endl; cout << &a << endl; cout << &b << endl; cout << &f << endl; variabili globali 0x407030 0x407034 0x407038 Data segment variabili locali cout << "variabili locali" << endl; 0x61fe34 0x61fe30 Stack cout << &c << endl; cout << &d << endl; cout << &g << endl; return 0; E222 Provate adesso sui vostri laptop! 162
163 3
0x61fe2c Process returned 0 (0x0) Press any key to continue. execution time : 1.131 s }
Fondamenti 2024-2025 - Secondo semestre 17/03/2025 Esempio int* p; p = new int; *p=10; heap p · dichiaro un puntatore · allocco nella heap lo spazio per un intero, cioè 4 byte . creo una zona di memoria che può contenere un intero · operatore new restituisce un puntatore che viene assegnato a p · attraverso il puntatore p posso accedere questo spazio di memoria e posso memorizzare un numero intero . In pratica, per i tipi semplici all. dinamica viene utilizzata raramente. Perché? 164 Esempio int* p; p = new int; *p=10; int+ pi *p=10; · dichiaro un puntatore · allocco nella heap lo spazio per un intero, cioè 4 byte · creo una zona di memoria che può contenere un intero · operatore new restituisce un puntatore che viene assegnato a p · attraverso il puntatore p posso accedere questo spazio di memoria e posso memorizzare un numero intero . In pratica, per i tipi semplici all. dinamica viene utilizzata raramente. Perché? 165 4Fondamenti 2024-2025 - Secondo semestre 17/03/2025
int a=0;int b=0; float f=0; Esperimento 2 int main() { int c=0; int d=0; float g=0; cout << "variabili globali" << endl; variabili globali 0x407030 Data segment cout << &a << endl << &b << endl << &f << endl cout << "variabili locali" << endl; 0x407034 0x407038 cout << &c << endl << &d << endl << &g << endvariabili locali 0x61fe4c 0x61fe48 0x61fe44 allocazione dinamica 0xf31760 0xf31780 Heap 0xf31ad0 cout << "allocazione dinamica " << endl cout << p << endl; cout << q << endl; cout << r << endl; altre variabili locali 0x61fe38 0x61fe30 Stack 0x61fe28 Process returned 0 (0x0) Press any key to continue. execution time : 0.435 s cout << "altre variabili locali" << endl; cout << &p << endl; cout << &q << endl; cout << &r << endl; wooclap return 0; Codice evento GQLROF } E222 Provate adesso sui vostri laptop! 166
- * P men inti HEAD Cout << Pt STACK Toutes & pG 0 167 5
1 Stack int *p = new int; int *q = new int; float *r = new float;
17/03/2025 Fondamenti 2024-2025 - Secondo semestre Esempio più interessante char* stringa; stringa = new char [30] ; heap stringa · dichiaro un puntatore ad un char · allocco nella heap lo spazio per 30 caratteri · operatore new restituisce un puntatore che viene assegnato a stringa · attraverso il puntatore stringa posso accedere questo spazio di memoria e posso memorizzare una sequenza di 30 caratteri 169
Operatore new · La dimensione dell'area di memoria da allocare si può definire a run-time. Ad esempio: int n; cout << "Inserire le dimensioni di una stringa"; cin >> n; char* stringa = new char [n] ; if (stringa != 0) cin >> stringa; · Nota: se la memoria disponibile è esaurita, new restituisce un puntatore nullo. Prima di de-referenziare il puntatore restituito da new, occorre quindi assicurarsi che sia valido! 170 6Fondamenti 2024-2025 - Secondo semestre 17/03/2025
Deallocazione · Un oggetto allocato dinamicamente resta allocato finché: - Non viene esplicitamente deallocato; - Il programma non termina. · In C++ non esiste un meccanismo automatico per recuperare la memoria allocata e non più utilizzata (garbage collection). · Pertanto, la memoria inutilizzata, ma non esplicitamente deallocata di norma non è più disponibile! 171
Operatore delete · L'operatore delete dealloca l'area di memoria, precedentemente allocata in modo dinamico, puntata da un puntatore: · Sintassi: delete puntatore ; delete [] puntatore; (per gli array) · Esempio: int *p; char *stringa; p = new int; stringa = new char [30] ; delete p; delete [] stringa; 172 717/03/2025 Fondamenti 2024-2025 - Secondo semestre
Vantaggi allocazione dinamica · Il meccanismo di allocazione e deallocazione dinamica della memoria consente: - La gestione efficiente delle risorse di memoria in modo da allocare solo lo spazio realmente necessario; - La creazione di strutture dati fatte da un numero di elementi che possono variare durante l'esecuzione del programma. · Occorre tuttavia usare con attenzione gli operatori new e delete! 173
Esempio 1: allocazione dinamica di array #include <iostream> using namespace std; int main() { int n; cout << "Inserire il numero di elementi: "; 1000 cin >> n; if (n <= 0) return -1; int* a = new int [n] ; if (a == 0) return -1; for (int i = 0; i < n; i++) a[i] = i + 1; for (int j = 0; j < n - 1; j++) cout << a[j] << ", "; cout << a[n - 1] << endl; delete [] a; return 0; } E037 174
817/03/2025 Fondamenti 2024-2025 - Secondo semestre Esempio 2: allocazione dinamica di stringhe #include <iostream> #include <cstring> using namespace std; int main () { 0000000 char s1[256]; char s2[256]; char* ps3; cout << "Inserire due stringhe: "; cin >> s1 >> s2; int dim1 = strlen (s1) ; int dim2 = strlen (s2) ; ps3 = new char [dim1+dim2+1] ; //allocazione if (ps3 == 0) return -1; strcpy (ps3, s1) ; strcat(ps3, s2); cout << "Stringa concatenata: " << ps3 << endl; delete [] ps3; //deallocazione return 0; } E038 175
Commento su delete · Libera la memoria allocata dinamicamente in modo che possa essere riallocata mediante successive chiamate dell'operatore new · Questo rende riutilizzabile la memoria puntata, ma non cancella il puntatore che può essere riutilizzato per puntare ad un'altra variabile successivamente allocata con new 176
917/03/2025 Fondamenti 2024-2025 - Secondo semestre Allocazione di diverse aree con lo stesso puntatore 9000000 int main() { int* a; for (int k = 0; k < 10000; k++) { a = new int[k]; · Posso usare lo stessa variabile di puntatore per allocare vari spazi nella memoria if (a == NULL) { · In questo codice c'è un errore. Dove? cout << "Memory allocation failed." << endl; return -1; } for (int i = 0; i < k; i++) a[i] = i + 1; for (int j = 0; j < k; j++) cout << a[j] << ", " } delete[] a; return 0; ? · Controllare l'uso della memoria nel Task Manager } E039 177 Allocazione di diverse aree con lo stesso puntatore 00 int main() { int* a; for (int k = 0; k < 10000; k++) { a = new int[k]; · Posso usare lo stessa variabile di puntatore per allocare vari spazi nella memoria if (a == NULL) { cout << "Memory allocation failed." << endl; return -1; } for (int i = 0; i < k; i++) a[i] = i + 1; for (int j = 0; j < k; j++) cout << a[j] << ", "; } · In questo codice c'è un errore. Dove? delete[] a; return 0; } E039 · Controlla l'uso della memoria nel Task Manager 178
1017/03/2025 Fondamenti 2024-2025 - Secondo semestre Allocazione di diverse aree con lo stesso puntatore int main() { int* a; • Versione corretta: for (int k = 0; k < 10000; k++) { a = new int[k]; if (a == NULL) { · in ogni ciclo di for, operatore delete dovrebbe liberare la memoria allocata con new cout << "Memory allocation failed." << endl; return -1; } for (int i = 0; i < k; i++) a[i] = i + 1; for (int j = 0; j < k; j++) cout << a[j] << ", "; delete[] a; } return 0; } · Ricontrolla l'uso della memoria nel Task Manager 179
Le strutture statiche Vs dinamiche const int n = 4; int a[n]; int *p; int n = 0; cin>>n; p = new int [n]; Strutture dinamiche, p.e., liste (vedremmo a maggio) • Non posso cambiare le dimensioni di a dopo la compilazione del programma · Una volta deciso il valore di n durante l'esecuzione del programma, non è più possibile modificare le dimensioni dell'array a cui punta p • è sempre possibile aggiungere nuovi elementi, · l'unico limite è la memoria disponibile. · Posso effettuare una riallocazione dinamica: – creo un nuovo array con n+1 elementi, – copio tutti gli elementi, cancello il vecchio array. – maggiore flessibilità 180
1117/03/2025 Fondamenti 2024-2025 - Secondo semestre Esempio di riallocazione int main() { int* array = new int[3];// Allocazione iniziale per un array di 3 int for (int i = 0; i < 3; ++i) array[i] = i * 10; // Inizializzazione ... int* newArray = new int [5]; // Riallocazione per un array di 5 interi // Copia dei valori dall'array originale al nuovo array for (int i = 0; i < 3; ++i) newArray[i] = array[i] ; delete[] array; // Deallocazione della memoria dell'array originale // Aggiunta di valori aggiuntivi al nuovo array for (int i = 3; i < 5; ++i) newArray[i] = i * 10; for (int i = 0; i < 5; ++i) cout << newArray[i] << " "; //stampa tutto delete[] newArray; // Deallocazione della memoria del nuovo array return 0; } E069 181 Esempio di riallocazione int main() { E069 int* array1 = new int [3]; for (int i = 0; i < 3; ++i) array1[i] = i * 10; // Inizializzazione cout << "Valori del array prima di riallocazione:" << endl; for (int i= 0; i < 3; ++i) cout << array1[i] << " "; cout << endl; int* newArray = new int[5]; // Riallocazione per un array di 5 interi for (int i = 0; i < 3; ++i) newArray[i] = array1[i]; //Copia dei valori delete[] array1; // Deallocazione della memoria dell'array originale array1=newArray; for (int i = 3; i < 5; ++i) array1[i] = i * 10; // Aggiunta di valori cout << "Valori del nuovo array dopo la riallocazione:" << endl; for (int i= 0; i < 5; ++i) cout << array1[i] << " "; delete[] array1; // Deallocazione della memoria del nuovo array return 0; } 9000000 182 12