Puntatori e memoria

L'aritmetica dei puntatori in C e C++

In questa lezione scorrerai gli elementi di un array con l'aritmetica dei puntatori in C e con gli iteratori in C++.

Introduzione

Quando aggiungi 1 a un puntatore, non avanza di 1 byte ma passa all'elemento successivo dell'array, perché il compilatore calcola lo spostamento in base alla dimensione del tipo. Così puoi usare i puntatori per scorrere un'area di memoria continua come un array.

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>

int main(void) {
    int values[] = {10, 20, 30, 40};
    int sum = 0;
    for (int *p = values; p < values + 4; ++p) sum += *p;
    printf("sum=%d distance=%td\n", sum, (values + 4) - values);
    return 0;
}
Risultato dell'esecuzione
sum=100 distance=4
C++
Esegui →
main.cpp
#include <iostream>
#include <vector>

int main() {
    std::vector values{10, 20, 30, 40};
    int sum = 0;
    for (auto it = values.begin(); it != values.end(); ++it) sum += *it;
    std::cout << "sum=" << sum << " distance="
              << std::distance(values.begin(), values.end()) << '\n';
}
Risultato dell'esecuzione
sum=100 distance=4

Confronto tra C e C++

Il ciclo parte con il puntatore p sul primo elemento e avanza finché p non raggiunge la posizione values + 4. A ogni passo, *p prende il valore corrente e lo aggiunge al totale. L'aritmetica dei puntatori è valida solo all'interno dello stesso array, o subito dopo l'ultimo elemento. In C++ gli iteratori permettono di scorrere allo stesso modo molti tipi diversi di contenitori.

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