Puntatori come Valori di ritorno di Funzioni in linguaggio C

Nella lezione precedente abbiamo visto come passare puntatori come argomenti di funzioni. In questa lezione vediamo come restituire puntatori da funzioni.

Puntatori restituiti da funzioni

Nella lezione precedente abbiamo visto che è possibile passare dei puntatori come argomento di funzioni. Con questa tecnica è possibile scrivere funzioni che restituiscono più valori di ritorno.

In questa lezione vediamo come realizzare funzioni che restituiscono puntatori.

Per fare questo partiamo da un esempio: vogliamo realizzare una funzione che presi in ingresso due puntatori a interi, restituisca il puntatore al minimo dei due.

Una possibile implementazione è la seguente:

int *min(int *x, int *y) {
    if (*x > *y) {
        return y;
    }
    else {
        return x;
    }
}

Volendo provare ad utilizzare la funzione, dobbiamo dapprima due variabili ed un puntatore per il valore di ritorno:

int *risultato;
int a, b;

printf("Inserisci due numeri interi:\n");
scanf("%d\n", &a);
scanf("%d\n", &b);

risultato = min(&a, &b);

Invocando la funzione min, x diventa a tutti gli effetti un alias per a mentre y diventa un alias per b. Se a è minore di b allora risultato conterrà l'indirizzo di a. In caso contrario conterrà l'indirizzo di b.

Una funzione può anche restituire l'indirizzo di una variabile esterna oppure ad una variabile locale purché dichiarata come static.

Nota

Mai restituire un puntatore ad una variabile locale

Un errore molto grave che può essere commesso nel restituire un puntatore da una funzione è quello di restituire l'indirizzo di una variabile locale:

int *funzione() {
    int x;

    /* ... */

    return &x;
}

Nell'esempio di sopra il problema sta nel fatto che stiamo restituendo l'indirizzo di x. Tuttavia, al termine della funzione, x cesserà di esistere per cui l'indirizzo restituito punterà ad una locazione di memoria non più valida.

In questi casi i compilatori spesso mostrano un messaggio di warning. Ad esempio gcc restituisce un messaggio del genere:

prova_puntatore_locale.c: In function ‘f’:
prova_puntatore_locale.c:5:12: warning: function returns address of local variable [-Wreturn-local-addr]
    5 |     return &x;
      |            ^~

Esempio: ricerca del massimo di un array e del suo indice

Vediamo, adesso, un esempio di applicazione in cui una funzione restituisce un puntatore.

Vogliamo scrivere una funzione, ricerca_massimo, che ricerca il massimo valore di un array e ne restituisca il puntatore. La funzione deve inoltre restituire l'indice associato.

Possiamo scrivere la funzione ricerca_massimo in questo modo:

int *ricerca_massimo(int a[], int n, int *i) {
    int j;
    *i = 0;
    int max = a[0];

    for (j = 1; j < n; ++j) {
        if (a[j] > max) {
            max = a[j];
            *i = j;
        }
    }

    return &a[*i];
}

In questo esempio, il parametro i viene utilizzato per memorizzare e restituire l'indice del valore massimo nell'array. La variabile locale max viene usata solo per cercare il valore massimo e quindi memorizza temporaneamente il massimo trovato finora.

Risulta interessante osservare l'espressione return finale. In questo caso stiamo restituendo l'indirizzo della locazione dell'array con indice pari a *i.

Un possibile programma completo che cerca il massimo e il suo indice in un array di 10 elementi è il seguente:

#include <stdio.h>

int *ricerca_massimo(int a[], int n, int *i);

int main() {
    const int n = 10;
    int a[n];
    int i;
    int *max;
    int indice_massimo;

    printf("Inserisci %d numeri:\n");

    for (i = 0; i < n; ++i) {
        scanf("%d\n", &a[i]);
    }

    max = ricerca_massimo(a, n, &indice_massimo);

    printf("Il massimo è %d e si trova in posizione %d\n", *max, indice_massimo);

    return 0;
}

int *ricerca_massimo(int a[], int n, int *i) {
    int j;
    *i = 0;
    int max = a[0];

    for (j = 1; j < n; ++j) {
        if (a[j] > max) {
            max = a[j];
            *i = j;
        }
    }

    return &a[*i];
}

Provando a compilare ed eseguire il programma un possibile output è il seguente:

Inserisci 10 numeri:
23
12
78
33
22
94
32
102
54
57
72
Il massimo è 102 e si trova in posizione 7

In Sintesi

In questa lezione abbiamo visto come realizzare funzioni che restituiscono puntatori. Con questa lezione abbiamo visto due possibili utilizzi dei puntatori.

A partire dalla prossima lezione inizieremo a studiare la stretta relazione che intercorre tra puntatori ed array.