Summaries

University notes in Markdown format from Obsidian.

Gestione della memoria

download Download MD

Puntatori

Le variabili puntatore contengono indirizzi di memoria di altre variabili. Mentre le variabili normali contengono un valore diretto (Riferimento Diretto), i puntatori contengono l'indirizzo di una variabile che ha uno specifico valore (Riferimento Indiretto) .

Dichiarazione: Si usa il simbolo * tra il tipo e il nome.

  • int *ptr; (Puntatore a un intero).
  • Attenzione: in dichiarazioni multiple l'asterisco va ripetuto: int *ptr1, *ptr2;.

Operatori Fondamentali:

  1. Indirizzo (&): Restituisce l'indirizzo di memoria della variabile.
    • Es. ptr = &x; (Assegna a ptr l'indirizzo di x).
  2. *Dereferenziazione (``):** Restituisce il valore dell'oggetto puntato (accede al contenuto all'indirizzo).
    • Es. cout << *ptr; (Stampa il valore della variabile puntata da ptr).
    • Nota: * e & sono operatori inversi: *&y == y.

Puntatori Nulli: Possono essere inizializzati a 0, NULL o nullptr (C++11). Dereferenziare un puntatore nullo causa un errore di Segmentation Fault (crash del programma). Puntatori Pendenti (Dangling Pointers): Un puntatore che punta a un'area di memoria non più valida (es. una variabile locale uscita dallo scope). Dereferenziarlo causa comportamento indefinito.

Puntatori e Costanti (const)

Il qualificatore const modifica il comportamento del puntatore:

  1. Puntatore a Costante: Il valore puntato non può cambiare, ma il puntatore può cambiare indirizzo.

    • const int *ptr = &x;
    • *ptr = 5; -> ERRORE
    • ptr = &y; -> OK.
  2. Puntatore Costante: L'indirizzo contenuto nel puntatore non può cambiare, ma il valore puntato sì. Deve essere inizializzato subito.

    • int * const ptr = &x;
    • ptr = &y; -> ERRORE
    • *ptr = 5; -> OK.
  3. Puntatore Costante a Costante: Né l'indirizzo né il valore possono cambiare.

    • const int * const ptr = &x;.

      Riferimenti (References)

      Un riferimento è un alias (un altro nome) per una variabile esistente.

    • Sintassi: int &ref = x;.
    • Qualsiasi operazione su ref ha effetto su x.

Regole e Differenze con i Puntatori:

  • Deve essere inizializzato alla dichiarazione.
  • Non può essere NULL.
  • Non può essere cambiato per riferirsi a un'altra variabile dopo l'inizializzazione (non si può "reseatare").

    Aritmetica dei Puntatori

    Operazioni valide sui puntatori (utili soprattutto con gli array):

    1. Incremento/Decremento (++, --): Sposta il puntatore alla locazione di memoria successiva/precedente in base alla dimensione del tipo di dato.
      • Es. Se int occupa 4 byte e ptr è 3000, ptr++ diventa 3004.
    2. Somma/Sottrazione Intero (+, -): Sposta il puntatore di N posizioni.
    3. Differenza tra Puntatori: Restituisce il numero di elementi tra due indirizzi.
    4. Relazione Array-Puntatori: Il nome di un array è un puntatore costante al primo elemento. V[i] è equivalente a *(V + i).

      Memoria Dinamica (Heap)

      La memoria allocata staticamente (es. int A[10]) è decisa a tempo di compilazione. Per decidere la quantità di memoria a tempo di esecuzione, si usa lo Heap (Free Store).

      Operatore new

      Alloca memoria nello Heap e restituisce un puntatore.

  • Variabile singola: int *p = new int(5); (alloca e inizializza a 5).
  • Array dinamico: int *arr = new int[dimensione];.

    Operatore delete

    Dealloca la memoria per evitare Memory Leaks (perdita di memoria).

  • Variabile singola: delete p;.
  • Array dinamico: delete[] arr; (fondamentale le parentesi quadre!).

Errori Comuni:

  1. Memory Leak: Dimenticare delete (la memoria rimane occupata fino al termine del programma).
  2. Double Free: Applicare delete due volte sullo stesso puntatore.
  3. Accesso dopo Delete: Usare un puntatore dopo aver liberato la memoria (il puntatore è dangling).

    Matrici Dinamiche

    Si realizzano come array di puntatori (puntatore a puntatore).

  4. Allocazione array di puntatori (righe): int **M = new int*[righe];
  5. Allocazione di ogni riga: M[i] = new int[colonne]; .
  6. Deallocazione inversa: prima le righe (delete[] M[i]), poi l'array di puntatori (delete[] M) .