Ciao
Peternek,
Peternek ha scritto:ho appena fatto un algoritmo [...]. Però so che ha uno stack interno..
Lo stack è del processo o del thread, non dell'algoritmo.
Lo spazio che richiede una chiamata ricorsiva dipende del compilatore, dalle dimensioni dei parametri che passi e da quelle delle variabili locali, dalle dimensioni dell'indirizzo di ritorno e da eventuali byte di allineamento:
A volte il chiamante riserva spazio sullo stack anche per il valore di ritorno della funzione, ma se questo è di un tipo che non occupa troppa memoria, generalmente viene ritornato in uno o più registri del processore.
Alcuni compilatori usano registri anche per passare i parametri che possono starci. Tuttavia in caso di successiva chiamata ricorsiva il chiamato dovrà comunque salvarli, quindi alla fine occuperanno spazio sullo stack. Lo stesso vale per le variabili locali.
Per sapere quanto occupa una chiamata ricorsiva della tua funzione sullo stack potresti stampare l'indirizzo di una qualsiasi delle variabili locali, per esempio:
- Codice: Seleziona tutto
printf("0x%08X\n", &dim);
e vedere di quanto cambia tra una chiamata e la successiva. La differenza tra i due indirizzi è la dimensione occupata sullo stack da ogni singola chiamata ricorsiva.
Nel tuo caso, ipotizzando che l'indirizzo di ritorno e ogni parametro e variabile locale (compresi eventuali byte di allineamento) occupino 32 bit (cioè 4 byte), siccome hai 4 parametri, 3 variabili locali e 1 indirizzo di ritorno, stimo che ogni chiamata ricorsiva occupi 64 byte di stack. Comunque dipende anche dal compilatore e dalle ottimizzazioni che imposti.
Per sapere la memoria totale occupata da tutta la catena di chiamate ricorsive dovresti conoscere la profondità massima di ricorsione (nel caso più sfortunato).
Ci sono algoritmi (per esempio il quicksort) dove si possono inserire modifiche apposta per evitare che si diano i casi più sfortunati, in modo da garantire che la massima quantità di stack occupata sia proporzionale, per esempio, a

e non a

(dove

è il numero di elementi da processare). Nel quicksort la garanzia si può ottenere con la scelta di eseguire sempre per prima la parte più corta (con ricorsioni meno profonde), in modo di non doverne mantenere il riferimento sullo stack quando si va ad eseguire la parte più lunga (con ricorsioni più profonde).
Ci sono anche algoritmi ricorsivi in cui si può sostituire la ricorsione con cicli (ad esempio il calcolo del fattoriale). Spesso si riconoscono perché hanno (o si può spostare) la chiamata ricorsiva all'inizio o alla fine della funzione.
Credo che anche la ricerca di una sottostringa palindroma si possa scrivere solo con cicli, senza ricorsione.
Negli altri casi si possono eliminare le chiamate ricorsive utilizzando internamente alla funzione uno stack, che però è solo un modo mascherato (magari più controllabile) di effettuare una ricorsione.
In applicazioni reali (non dimostrative) la ricorsione è da evitare il più possibile perché non permette al compilatore di sapere in tempo di compilazione la quantità di stack occupata da un processo. Questo obbliga a una gestione più complessa e aggiunge la possibilità che la memoria disponibile non sia sufficiente a terminare l'esecuzione, con conseguenze reali che possono essere catastrofiche. Infatti la ricorsione è una delle cose vietate dalle regole MISRA C, che si applicano in software di controllo veicolare e avionico.