Tipi di Allocazione della Memoria

Nel linguaggio C, l’allocazione della memoria può essere suddivisa in tre categorie principali:

  1. Allocazione Statica:

    • Le variabili globali e statiche vengono allocate nel segmento dati quando il programma viene caricato in memoria e rimangono allocate per tutta la durata dell’esecuzione del programma.
  2. Allocazione Automatica:

    • Le variabili locali e gli argomenti delle funzioni vengono allocate nello stack. Lo spazio viene creato all’ingresso di una funzione e liberato automaticamente all’uscita.
  3. Allocazione Dinamica:

    • Questo tipo di allocazione utilizza l’heap (o free store) per gestire la memoria durante l’esecuzione del programma. È necessario gestirla manualmente tramite funzioni della libreria standard come malloc, calloc, realloc e free.

Funzioni per l’Allocazione Dinamica

  1. malloc

    • Prototipo: void* malloc(size_t size);
    • Alloca un blocco di memoria contiguo di dimensione specificata in byte.
    • Restituisce un puntatore generico (void*) che deve essere convertito al tipo desiderato.
    • Se l’allocazione fallisce, restituisce NULL.
    • Esempio:
      int* array = (int*)malloc(10 * sizeof(int));
      if (array == NULL) {
          // Gestione errore
      }
  2. calloc

    • Prototipo: void* calloc(size_t num, size_t size);
    • Alloca memoria per un numero specificato di elementi e la inizializza a zero.
    • Esempio:
      int* array = (int*)calloc(10, sizeof(int));
      if (array == NULL) {
          // Gestione errore
      }
  3. realloc

    • Prototipo: void* realloc(void* ptr, size_t size);
    • Ridimensiona un blocco di memoria precedentemente allocato con malloc o calloc.
    • Può spostare il contenuto in un nuovo blocco se non c’è spazio contiguo sufficiente.
    • Esempio:
      array = (int*)realloc(array, 20 * sizeof(int));
      if (array == NULL) {
          // Gestione errore
      }
  4. free

    • Prototipo: void free(void* ptr);
    • Libera la memoria precedentemente allocata con malloc, calloc o realloc.
    • È essenziale per evitare perdite di memoria.
    • Esempio:
      free(array);

Allocazione Dinamica di Strutture Complesse

  1. Array Monodimensionali:

    • Esempio:
      int* array = (int*)malloc(10 * sizeof(int));
      for (int i = 0; i < 10; i++) {
          array[i] = i;
      }
      free(array);
  2. Array Multidimensionali:

    • Primo metodo:
      int** matrix = (int**)malloc(3 * sizeof(int*));
      for (int i = 0; i < 3; i++) {
          matrix[i] = (int*)malloc(4 * sizeof(int));
      }
      // Liberazione della memoria
      for (int i = 0; i < 3; i++) {
          free(matrix[i]);
      }
      free(matrix);
    • Secondo metodo (blocco unico):
      int* matrix = (int*)malloc(3 * 4 * sizeof(int));
      for (int i = 0; i < 3; i++) {
          for (int j = 0; j < 4; j++) {
              matrix[i * 4 + j] = i + j;
          }
      }
      free(matrix);

Vantaggi e Svantaggi dell’Allocazione Dinamica

  • Vantaggi:

    • Permette una gestione flessibile della memoria.
    • Ideale per strutture di dati dinamiche come liste, alberi e grafi.
  • Svantaggi:

    • Richiede una gestione esplicita della memoria.
    • Errori comuni includono perdite di memoria (memory leaks) e accessi a memoria non valida (dangling pointers).

Best Practices

  1. Inizializzare sempre i puntatori a NULL.
  2. Verificare il successo dell’allocazione prima di utilizzare la memoria.
  3. Liberare la memoria appena non è più necessaria.
  4. Evitare doppi free, che possono causare comportamenti indefiniti.

Domande Potenziali

  1. Quali sono le principali differenze tra allocazione statica, automatica e dinamica?
  2. Come funziona la funzione malloc e perché è necessario usare sizeof?
  3. Qual è la differenza tra malloc e calloc?
  4. Quando si usa realloc e quali sono i possibili rischi?
  5. Quali sono le implicazioni di una mancata chiamata a free su un blocco di memoria?
  6. Come si alloca dinamicamente un array bidimensionale e quali sono le differenze tra i diversi approcci?
  7. Che cosa sono i dangling pointers e come si possono evitare?
  8. Quali sono i rischi associati alla gestione manuale della memoria e come possono essere mitigati?