Il punto di ritorno

I record di attivazione delle funzioni non contengono soltanto le variabili locali delle funzioni. Un'altra cosa che si trova nel record di attivazione di ogni funzione è il punto di ritorno, ossia il punto in cui la funzione è stata chiamata, e a cui deve ritornare. In altre parole: una funzione A viene attivata perchè un'altra funzione B la ha chiamata; quando A termina, occorre ricominciare con la istruzione di B che segue la chiamata di funzione. Il punto di ritorno di ogni funzione indica appunto quale è la istruzione da cui occorre ricominciare la funzione chiamante quando la funzione termina.

Consideriamo il seguente programma di esempio ritorno.c

/*
  Esempio che mostra il punto di ritorno.
*/

void Esempio(int x) {
  if(x<=0)
    return;

  printf("%d ", x);

  Esempio(x-1);

  printf("%d ", -x);
}

int main() {
  Esempio(4);

  return 0;
}


Ci chiediamo cosa fa il programma. La funzione viene chiamata con il valore 4, per cui il primo record di attivazione contiene una variabile x il cui valore è 4. Questo valore viene stampato. Viene poi chiamata ricorsivamente la funzione, passando il valore x-1, ossia 3. Il nuovo record di attivazione contiene quindi una variabile x in cui c'è 3, che viene stampato. Si arriva in questo modo a una chiamata in cui viene passato 0. Fino a questo punto, sono stati stampati i valori 4 3 2 1.

Quando la funzione viene chiamata con argomento 0, si crea l'ultimo record di attivazione, quello in cui la x contiene 0. Dato che la condizione x<=0 è vera, si esce dalla funzione senza fare la chiamata ricorsiva. Cosa succede? Come per tutte le funzioni, si continua la esecuzione della funzione chiamante.

Questo significa che occorre ripartire con la istruzione che segue la chiamata di funzione. Il punto in cui occorre ricominciare viene memorizzato nel record di attivazione della funzione. In altre parole, il record di attivazione di una funzione non contiene solo le variabili locali, ma anche il punto in cui occorre ritornare quando la funzione stessa termina.

Il punto di ritorno, quando serve, lo indichiamo scrivendo il codice a fianco dello stack, e mettendo una freccia che parte dal record di attivazione e punta alla istruzione in cui la funzione è stata attivata. Nel nostro caso, abbiamo una situazione del genere:

Quando la funzione viene chiamata con parametro 0, termina immediatamente. Quando una funzione termina, si fanno due cose:

  1. si dealloca il record di attivazione (si libera la memoria);
  2. si ritorna ad eseguire a partire dal punto indicato dal punto di ritorno.

Questo significa che si delloca il record di attivazione che contiene la x che vale 0, e si esegue la istruzione printf("%d ", x);. Questa istruzione usa il valore di x che si trova nel record di attivazione più in alto, per cui stampa -1, dato che lo stato dello stack, dopo la deallocazione dell'ultimo record, è il seguente:

Vale la pena di notare che le variabili che vengono usate sono sempre e solo quelle del record di attivazione più in alto: infatti, quando si esegue una funzione, le variabili allocate per esse sono comunque quelle dell'ultimo record di attivazione creato.

Dopo l'ultima istruzione di stampa, la funzione termina. Si dealloca il record di attivazione, e si riparte dal punto di ritorno scritto nel record di attivazione. Abbiamo quindi la seguente situazione, in cui si esegue la istruzione printf("%d ", -x);

La x che si usa è ancora quella del record che si trova in cima allo stack, per cui si stampa -2. La funzione termina, per cui si fa nuovamente la dellocazione, e si va al punto di ritorno. Ossia si esegue di nuovo la stampa, dopo aver dellocato il record.

Si stampa quindi il valore -3, dato che la x del record più in alto è 3. Si fa di nuovo la deallocazione e si va al punto di ritorno:

Questo significa che si stampa -4, e si termina la funzione. Il record viene deallocato, e si torna al punto di ritorno, che questa volta è all'interno di main, per cui si esegue quello che resta del main (nell'esempio, non ci sono altre istruzioni, per cui il programma termina).