Puntatori e memoria

La gestione della memoria dinamica in C e C++

In questa lezione allocherai un array la cui dimensione viene decisa durante l'esecuzione e libererai quella memoria in modo sicuro.

Introduzione

La memoria dinamica si usa quando la dimensione o la durata dei dati non si può stabilire in fase di compilazione, per esempio quando il numero di elementi dipende da ciò che inserisce l'utente. Questa memoria viene allocata mentre il programma è in esecuzione e va liberata quando non serve più.

Punti importanti

  • Un puntatore deve puntare solo a un oggetto che esiste ancora, del tipo giusto, oppure essere nullo.
  • Ogni area di memoria allocata va liberata esattamente una volta.
  • Rendi chiaro quale funzione possiede la memoria (ownership) e quali dati sono solo letti (const).

Esempi di codice C e C++

C
Esegui →
main.c
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    size_t count = 5;
    int *values = calloc(count, sizeof *values);
    if (!values) return 1;
    for (size_t i = 0; i < count; ++i) values[i] = (int)(i * i);
    printf("last=%d\n", values[count - 1]);
    free(values);
    return 0;
}
Risultato dell'esecuzione
last=16
C++
Esegui →
main.cpp
#include <iostream>
#include <vector>

int main() {
    std::vector<int> values(5);
    for (std::size_t i = 0; i < values.size(); ++i) values[i] = static_cast<int>(i * i);
    std::cout << "last=" << values.back() << '\n';
}
Risultato dell'esecuzione
last=16

Confronto tra C e C++

In C, calloc alloca la memoria per 5 interi e li inizializza a 0. Il programma deve controllare se l'allocazione è fallita e chiamare free alla fine per liberare la memoria; se te ne dimentichi, si verifica una perdita di memoria (memory leak). In C++, std::vector gestisce da solo la propria memoria e la libera quando non è più usata, anche se si verifica un'eccezione.

C

Il possesso e la liberazione della memoria sono interamente a carico del programmatore.

C++

Contenitori e RAII liberano automaticamente le risorse quando l'oggetto arriva alla fine della sua vita.

Esercizi di approfondimento

Esegui entrambe le versioni e poi modifica il codice per osservare la differenza di sicurezza che offre ciascun linguaggio.

  • Prova con puntatori nulli e allocazioni di memoria fallite.
  • Esegui il programma con AddressSanitizer e UndefinedBehaviorSanitizer per trovare errori di memoria.
  • Annota chiaramente quale puntatore possiede la memoria e quale serve solo per leggere.

Esercitati con una sfida

Usa ciò che questa lezione spiega per risolvere un problema reale. Ogni sfida gira nel browser, con test immediati e una revisione dell'IA.

Tutte le sfide