Fondamenti di Informatica T. Linguaggio C: Stack e Ricorsione

Documenti analoghi
Esercitazione 4. Comandi iterativi for, while, do-while

PROGRAMMAZIONE STRUTTURATA

Linguaggio C: introduzione

Le Strutture di controllo Del Linguaggio C. Prof. Francesco Accarino IIS Altiero Spinelli Sesto San Giovanni

Corso di Laurea Ingegneria Informatica Fondamenti di Informatica 1

UNIVERSITÀ DEGLI STUDI DI PAVIA FACOLTÀ DI INGEGNERIA. Matlab: esempi ed esercizi

Istruzioni di ciclo. Unità 4. Corso di Laboratorio di Informatica Ingegneria Clinica BCLR. Domenico Daniele Bloisi

Corso di Fondamenti di Informatica Classi di istruzioni 2

Una funzione è detta ricorsiva se chiama, direttamente o indirettamente, se stessa. In C tutte le funzioni possono essere usate ricorsivamente.

Fondamenti di Informatica. Algoritmi di Ricerca e di Ordinamento

giapresente( ) leggi( ) char * strstr(char * cs, char * ct) NULL

Diagrammi a blocchi 1

Ricorsione. Corso di Fondamenti di Informatica

L accesso ai dispositivi esterni (tastiera, monitor, file,...) viene gestito mediante canali di comunicazione.

ESAME DI FONDAMENTI DI INFORMATICA I ESAME DI ELEMENTI DI INFORMATICA. 28 Gennaio 1999 PROVA SCRITTA

Introduzione al Linguaggio C ed all IDE DEV-C++

Informatica Teorica. Macchine a registri

= < < < < < Matematica 1

Programmazione Ricorsione

Roadmap. Ricorsione: funzioni ricorsive. Definizione di fattoriale. Definizione dei numeri Fibonacci

Somma di numeri floating point. Algoritmi di moltiplicazione e divisione per numeri interi

Introduzione alle macchine a stati (non definitivo)

float somma_float(float a, float b) int get_ascii(char c)

Programmazione. Cognome... Nome... Matricola... Prova scritta del 22 settembre Negli esercizi proposti si utilizzano le seguenti classi:

Istruzioni iterative. Istruzioni iterative

Array multidimensionali e stringhe

Un esempio di if annidati

Programmazione Orientata agli Oggetti in Linguaggio Java

Laboratorio di Programmazione Lezione 1. Cristian Del Fabbro

DOCUMENTAZIONE WEB RAIN - ACCESSO CLIENTI

AA LA RICORSIONE

Unità Didattica 3 Linguaggio C. Generalità sulle Funzioni. Variabili locali e globali. Passaggio di parametri per valore.

Lezione 4. Sommario. L artimetica binaria: I numeri relativi e frazionari. I numeri relativi I numeri frazionari

Mini-Corso di Informatica

Tecniche per risolvere problemi: riduzione a sottoproblemi più semplici. Ricorsione

Ingegneria del Software

Il programma OCTAVE per l insegnamento dell algebra lineare nella Scuola Secondaria p. 1

Individuazione di sottoproblemi

= 300mA. Applicando la legge di Ohm su R4 si calcola facilmente V4: V4 = R4

Cos è un algoritmo. Si dice algoritmo la descrizione di un metodo di soluzione di un problema che sia

ARCHITETTURA DI UN SISTEMA DI ELABORAZIONE

Informatica B. Sezione D. Scuola di Ingegneria Industriale Laurea in Ingegneria Energetica Laurea in Ingegneria Meccanica

RICORSIONE - schema ricorsivo (o induttivo) si esegue l'azione S, su un insieme di dati D, mediante eventuale esecuzione di

Fondamenti di Programmazione

4 GLI ARRAY E LE STRINGHE

Variabili. Unità 2. Domenico Daniele Bloisi. Corso di Programmazione e Metodi Numerici Ingegneria Aerospaziale BAER

Uso di metodi statici. Walter Didimo

Funzioni. Corso di Fondamenti di Informatica

ADT Coda con priorità

Heap e code di priorità

Rappresentazioni numeriche

Appunti di informatica. Lezione 4 anno accademico Mario Verdicchio

Introduzione a Visual Basic Lezione 2 Cicli e anomalie

Algoritmi. Un tema centrale dell informatica è lo studio degli algoritmi.

Il concetto di calcolatore e di algoritmo

FONDAMENTI DI INFORMATICA Lezione n. 11

Informatica A a.a. 2010/ /02/2011

Classi. Oggetti e classi. Creazione e inizializzazione di oggetti in C++ Distruzione di oggetti in C++

Informatica/ Ing. Meccanica/ Prof. Verdicchio/ 14/02/2012 / Foglio delle domande / VERSIONE 1

Codice Gray. (versione Marzo 2007)

Il generatore di numeri casuali

Esercizi sulla conversione tra unità di misura

2.3 Cammini ottimi. E. Amaldi Fondamenti di R.O. Politecnico di Milano 1

1 DESCRIZIONE DELLE FUNZIONI REGISTRAZIONE UTENZE INTERNET Caricamento utente internet (data entry)... 3

Esempio : i numeri di Fibonacci

Esame Laboratorio di Sistemi Operativi Cognome Nome Mat.

Istruzioni di ripetizione in Java 1

Programmazione. Cognome... Nome... Matricola... Prova scritta del 11 luglio 2014

Creare una funzione float square(float x). La funzione deve restituire il quadrato del parametro x.

FILIPPO GIOVANOLLA CLASSE IV A MERCURIO PROGRAMMA PASCAL E C++ DISEQUAZIONI DI PRIMO E SECONDO GRADO

Strutture di accesso ai dati: B + -tree

Ricorsione. Unità 5. Domenico Daniele Bloisi. Corso di Fondamenti di Informatica Ingegneria delle Comunicazioni BCOR Ingegneria Elettronica BELR

Alberi binari di ricerca

La gestione dei caratteri in C

1 Definizione di sistema lineare omogeneo.

Codice binario. Codice. Codifica - numeri naturali. Codifica - numeri naturali. Alfabeto binario: costituito da due simboli

Esercitazione 7. Procedure e Funzioni

INFORMATICA GENERALE Prof. Alberto Postiglione Dipartimento Scienze della Comunicazione Università degli Studi di Salerno

Macchine RAM. API a.a. 2013/2014 Gennaio 27, 2014 Flavio Mutti, PhD

ESAME DI FONDAMENTI DI INFORMATICA I ESAME DI ELEMENTI DI INFORMATICA. 28 Gennaio 1999 PROVA SCRITTA

04 - Numeri Complessi

Gli array. Gli array. Gli array. Classi di memorizzazione per array. Inizializzazione esplicita degli array. Array e puntatori

Gestione Stato di Famiglia

Elementi base per la realizzazione dell unità di calcolo

COSTRUZIONE DI UN APPLICAZIONE

Esame Informatica Generale 13/04/2016 Tema A

int f(char *s, short n, float x) {... } /* definizione di f */ int f(char *, short, float); /* prototipo di f */

ESERCIZIO: CODICE FISCALE

Fondamenti VBA. Che cos è VBA

Risoluzione di problemi ingegneristici con Excel

COMPILAZIONE DELLA DOMANDA ON LINE

9. Modello di Esecuzione di un Programma C

La divisione esatta fra a e b è l operazione che dati i numeri a e b (con a multiplo di b) permette di trovare un terzo numero c tale che c b = a.

(1) (2) (3) (4) 11 nessuno/a (1) (2) (3) (4) X è il minore tra A e B nessuno/a X è sempre uguale ad A X è il maggiore tra A e B

Programmazione ad Oggetti

Corso di Laurea Ingegneria Informatica Fondamenti di Informatica

Procedura operativa per la gestione della funzione di formazione classi prime

Esercizi per il recupero del debito formativo:

Problema: calcolare il massimo tra K numeri

Il file system. Le caratteristiche di file, direttorio e partizione sono del tutto indipendenti dalla natura e dal tipo di dispositivo utilizzato.

Transcript:

Linguaggio C: Stack e Ricorsione

FUNZIONI: IL MODELLO A RUN-TIME Ogni volta che viene invocata una funzione: si crea di una nuova attivazione (istanza) del servitore viene allocata la memoria per i parametri e per le variabili locali si effettua il passaggio dei parametri si trasferisce il controllo al servitore si esegue il codice della funzione

Record di Attivazione Al momento dell invocazione: viene creata dinamicamente una struttura dati che contiene i binding dei parametri e degli identificatori definiti localmente alla funzione detta RECORD DI ATTIVAZIONE.

È il mondo della funzione : contiene tutto ciò che serve per la chiamata alla quale e` associato: i parametri formali le variabili locali Record di Attivazione l indirizzo di ritorno (Return address ) che indica il punto a cui tornare (nel codice del cliente) al termine della funzione, per permettere al cliente di proseguire una volta che la funzione termina. un collegamento al record di attivazione del cliente (Link Dinamico DL) l'indirizzo del codice della funzione (puntatore alla prima istruzione del corpo)

Record di Attivazione Puntatore al codice Return address Link dinamico Parametro 1 Parametro 2... Variabile locale 1 Dimensione del record (non fissa) Variabile locale 2...

Il record di attivazione associato a una chiamata di una funzione f: Record di Attivazione è creato al momento della invocazione di f permane per tutto il tempo in cui la funzione f è in esecuzione è distrutto (deallocato) al termine dell esecuzione della funzione stessa. Ad ogni chiamata di funzione viene creato un nuovo record, specifico per quella chiamata di quella funzione La dimensione del record di attivazione varia da una funzione all altra per una data funzione, è fissa e calcolabile a priori

Record di Attivazione Funzioni che chiamano altre funzioni danno luogo a una sequenza di record di attivazione allocati secondo l ordine delle chiamate deallocati in ordine inverso La sequenza dei link dinamici costituisce la cosiddetta catena dinamica, che rappresenta la storia delle attivazioni ( chi ha chiamato chi )

Stack L area di memoria in cui vengono allocati i record di attivazione viene gestita come una pila : STACK E` una struttura dati gestita a tempo di esecuzione con politica LIFO (Last In, First Out - l ultimo a entrare è il primo a uscire) nella quale ogni elemento e` un record di attivazione. La gestione dello stack avviene mediante due operazioni: Attivaz.3 Attivaz.2 Attivaz.1 push: aggiunta di un elemento (in cima alla pila) pop: prelievo di un elemento (dalla cima della pila)

Stack L'ordine di collocazione dei record di attivazione nello stack indica la cronologia delle chiamate: Push Pop att 2 att 1

Record di Attivazione Normalmente lo STACK dei record di attivazione si disegna nel modo seguente: sequenza attivazioni Quindi, se la funzione A chiama la funzione B, lo stack evolve nel modo seguente A chiama B e B poi B finisce passa il e il controllo A controllo a B A torna ad A A

Esempio: chiamate annidate Programma: int R(int A) { return A+1; int Q(int x) { return R(x); int P(void) { int a=10; return Q(a); main() { int x = P(); Sequenza chiamate: S.O. main P() Q() R()

Esempio: chiamate annidate Sequenza chiamate: S.O. main P() Q() R() R sequenza attivazioni Q P main

Spazio di indirizzamento La memoria allocata a ogni programma in esecuzione e` suddivisa in varie parti (segmenti), secondo lo schema seguente: code segment: contiene il codice eseguibile del programma code segment data segment data segment: contiene le variabili globali heap: contiene le variabili dinamiche stack: e` l'area dove vengono allocati i record di attivazione heap stack Code segment e data segment sono di dimensione fissata staticamente (a tempo di compilazione). La dimensione dell'area associata a stack + heap e` fissata staticamente: man mano che lo stack cresce, diminuisce l'area a disposizione dell'heap, e viceversa.

Variabili static E` possibile imporre che una variabile locale a una funzione abbia un tempo di vita pari al tempo di esecuzione dell'intero programma, utilizzando il qualificatore static: void f() { static int cont=0;... la variabile static int cont: e` creata all'inizio del programma, inizializzata a 0, e deallocata alla fine dell'esecuzione; la sua visibilita` e` limitata al corpo della funzione f, il suo tempo di vita e` pari al tempo di esecuzione dell'intero programma e` allocata nell'area dati globale (data segment)

#include <stdio.h> int f() { static int cont=0; main() cont++; return cont; { printf("%d\n", f()); printf("%d\n", f()); Esempio la variabile static int cont, e` allocata all'inizio del programma e deallocata alla fine dell'esecuzione; essa persiste tra una attivazione di f e la successiva: la prima printf stampa 1, la seconda printf stampa 2.

La ricorsione Una funzione matematica è definita ricorsivamente quando nella sua definizione compare un riferimento a se stessa La ricorsione consiste nella possibilità di definire una funzione mediante se stessa. È basata sul principio di induzione matematica: se una proprietà P vale per n=n 0 CASO BASE e si può provare che, assumendola valida per n, allora vale per n+1 allora P vale per ogni n>=n 0

La ricorsione Operativamente, risolvere un problema con un approccio ricorsivo comporta di identificare un caso base (n=n0) in cui la soluzione sia nota di riuscire a esprimere la soluzione al caso generico n in termini dello stesso problema in uno o più casi più semplici (n-1, n-2, etc).

La ricorsione: esempio Esempio: il fattoriale di un numero naturale fact(n) = n! n!: N N n! vale 1 se n == 0 n! vale n*(n-1)! se n > 0

Ricorsione in C In C e` possibile definire funzioni ricorsive: Il corpo di ogni funzione ricorsiva contiene almeno una chiamata alla funzione stessa. Esempio: definizione in C della funzione ricorsiva fattoriale. int fact(int n) { if (n==0) return 1; else return n*fact(n-1);

Ricorsione in C: esempio Servitore & Cliente: fact e` sia servitore che cliente (di se stessa): int fact(int n) { if (n==0) return 1; main() else return n*fact(n-1); { int fz,f6,z = 5; fz = fact(z-2);

Ricorsione in C: esempio Servitore & Cliente: int fact(int n) { if (n==0) return 1; else return n*fact(n-1); main(){ int fz,f6,z = 5; fz = fact(z-2); Si valuta l espressione che costituisce il parametro attuale (nell environment del main) e si trasmette alla funzione fatt una copia del valore così ottenuto (3).

Servitore & Cliente: Ricorsione in C: esempio int fact(int n) { if (n==0) return 1; else return n*fact(n-1); main(){ int fz,f6,z = 5; fz = fact(z-2); La funzione fact lega il parametro n a 3. Essendo 3 positivo si passa al ramo else. Per calcolare il risultato della funzione e necessario effettuare una nuova chiamata di funzione fact(2)

Servitore & Cliente: Ricorsione in C: esempio int fact(int n) { if (n==0) return 1; else return n*fact(n-1); main(){ int fz,f6,z = 5; fz = fact(z-2); La funzione fact lega il parametro n a 3. Essendo 3 positivo si passa al ramo else. Per calcolare il risultato della funzione e necessario effettuare una nuova chiamata di funzione. n-1 nell environment di fact vale 2 quindi viene chiamata fact(2)

Ricorsione in C: esempio Servitore & Cliente: int fact(int n) { if (n==0) return 1; else return n*fact(n-1); main(){ int fz,f6,z = 5; fz = fact(z-2); Il nuovo servitore lega il parametro n a 2. Essendo 2 positivo si passa al ramo else. Per calcolare il risultato della funzione e necessario effettuare una nuova chiamata di funzione. n-1 nell environment di fact vale 1 quindi viene chiamata fact(1)

Servitore & Cliente: Ricorsione in C: esempio int fact(int n) { if (n==0) return 1; else return n*fact(n-1); main(){ int fz,f6,z = 5; fz = fact(z-2); Il nuovo servitore lega il parametro n a 1. Essendo 1 positivo si passa al ramo else. Per calcolare il risultato della funzione e necessario effettuare una nuova chiamata di funzione. n-1 nell environment di fact vale 0 quindi viene chiamata fact(0)

Servitore & Cliente: Ricorsione in C: esempio int fact(int n) { if (n==0) return 1; else return n*fact(n-1); main(){ int fz,f6,z = 5; fz = fact(z-2); Il nuovo servitore lega il parametro n a 0. La condizione n <=0 e vera e la funzione fact(0) torna come risultato 1 e termina.

Servitore & Cliente: Ricorsione in C: esempio Il controllo torna al servitore precedente fact(1) che puo valutare l espressione n * 1 int fact(int n) { if (n==0) return 1; else return n*fact(n-1); main(){ int fz,f6,z = 5; fz = fact(z-2); (valutando n nel suo environment dove vale 1) ottenendo come risultato 1 e terminando.

Servitore & Cliente: Ricorsione in C: esempio int fact(int n) { if (n==0) return 1; else return n*fact(n-1); main(){ int fz,f6,z = 5; fz = fact(z-2); Il controllo torna al servitore precedente fact(2) che puo valutare l espressione n * 1 (valutando n nel suo environment dove vale 2) ottenendo come risultato 2 e terminando.

Servitore & Cliente: Ricorsione in C: esempio int fact(int n) { if (n==0) return 1; else return n*fact(n-1); main(){ int fz,f6,z = 5; fz = fact(z-2); Il controllo torna al servitore precedente fact(3) che puo valutare l espressione n * 2 (valutando n nel suo environment dove vale 3) ottenendo come risultato 6 e terminando. IL CONTROLLO PASSA AL MAIN CHE ASSEGNA A fz IL VALORE 6

Ricorsione in C: esempio fact(3) fact(2) fact(1) fact(0) main fact(3) fact(2) fact(1) fact(0) 3*2=6 2*1=2 1*1=1 1 main fact(3) fact(2) fact(1) fact(0) Cliente di fact(3) Cliente di fact(2) Servitore del main Cliente di fact(1) Servitore di fact(3) Cliente di fact(0) Servitore di fact(2) Servitore di fact(1)

Cosa succede nello stack? int fact(int n) { if (n==0) return 1; else return n*fact(n-1); main(){ int fz,f6,z = 5; fz = fact(z-2); NOTA: Anche il main()e una funzione Seguiamo l'evoluzione dello stack durante l'esecuzione:

Cosa succede nello stack? Situazione iniziale Il main() chiama fact(3) fact(3) chiama fact(2) fact(2) chiama fact(1) fact(1) chiama fact(0) main main main main main fact(3) fact(3) fact(3) fact(3) fact(2) fact(2) fact(2) fact(1) fact(1) fact(0)

Cosa succede nello stack? fact(0) termina restituendo il valore 1. Il controllo torna a fact(1) fact(1) effettua la moltiplicazione e termina restituendo il valore 1. Il controllo torna a fact(2) fact(2) effettua la moltiplicazione e termina restituendo il valore 2. Il controllo torna a fact(3) fact(6) effettua la moltiplicazione e termina restituendo il valore 6. Il controllo torna al main. 1 main fact(3) fact(2) fact(1) fact(0) 1 main fact(3) fact(2) fact(1) 2 main fact(3) fact(2) 6 main fact(3)

Esempio: somma dei primi N naturali Problema: calcolare la somma dei primi N naturali Specifica: Considera la somma 1+2+3+...+(N-1)+N come composta di due termini: (1+2+3+...+(N-1)) N Valore noto Il primo termine non è altro che lo stesso problema in un caso più semplice: calcolare la somma dei primi N-1 interi Esiste un caso banale ovvio: CASO BASE la somma fino a 1 vale 1.

Esempio: somma dei primi N naturali Problema: calcolare la somma dei primi N naturali Algoritmo ricorsivo: Somma: N -> N Somma(n) vale 1 se n == 1 Somma(n) vale n+somma(n-1) se n > 0

Esempio: somma dei primi N naturali Codifica: int sommafinoa(int n) { if (n==1) return 1; else return sommafinoa(n-1)+n;

Esempio: somma dei primi N naturali #include<stdio.h> int sommafinoa(int n); main() { int dato; printf("\ndammi un intero positivo: "); scanf("%d", &dato); if (dato>0) printf("\nrisultato: %d", sommafinoa(dato)); else printf("errore!"); int sommafinoa(int n) { if (n==1) return 1; else return sommafinoa(n-1)+n; Esercizio: seguire l'evoluzione dello stack nel caso in cui dato=4.

Calcolo iterativo del fattoriale Il fattoriale puo` essere anche calcolato mediante un'algoritmo iterativo: int fact(int n){ int i; int F=1; /*inizializzazione del fattoriale*/ for (i=2;i <= n; i++) F=F*i; return F; DIFFERENZA CON LA VERSIONE RICORSIVA: ad ogni passo viene accumulato un risultato intermedio

Calcolo iterativo del fattoriale int fact(int n){ int i; int F=1; /*inizializzazione del fattoriale*/ for (i=2;i <= n; i++) F=F*i; return F; La variabile F accumula risultati intermedi: se n = 3 inizialmente F=1 poi al primo ciclo for i=2 F assume il valore 2. Infine all ultimo ciclo for i=3 F assume il valore 6. Al primo passo F accumula il fattoriale di 1 Al secondo passo F accumula il fattoriale di 2 Al i-esimo passo F accumula il fattoriale di i

Processo computazionale iterativo Nell'esempio precedente il risultato viene sintetizzato in avanti L'esecuzione di un algoritmo di calcolo che computi in avanti, per accumulo, e` un processo computazionale iterativo. La caratteristica fondamentale di un processo computazionale iterativo è che a ogni passo è disponibile un risultato parziale dopo k passi, si ha a disposizione il risultato parziale relativo al caso k questo non è vero nei processi computazionali ricorsivi, in cui nulla è disponibile finché non si è giunti fino al caso elementare.

Esercizio Scrivere una funzione ricorsiva print_rev che, data una sequenza di caratteri (terminata dal carattere '.')stampi i caratteri della sequenza in ordine inverso. La funzione non deve utilizzare stringhe. Ad esempio: " parola " " alorap " funzione print_rev

Esercizio Osservazione: l'estrazione (pop) dei record di attivazione dallo stack avviene sempre in ordine inverso rispetto all'ordine di inserimento (push). associamo ogni carattere letto a una nuova chiamata ricorsiva della funzione Soluzione: void print_rev(char car); { char c; if (car!= '.') { scanf("%c", &c); print_rev(c); printf("%c", car); else return; ogni record di attivazione nello stack memorizza un singolo carattere letto (push); in fase di pop, i caratteri vengono stampati nella sequenza inversa

Soluzione #include <stdio.h> #include <string.h> void print_rev(char car); main() { char k; printf("\nintrodurre una sequenza terminata da.:\t"); scanf("%c", &k); print_rev(k); printf("\n*** FINE ***\n ); void print_rev(char car) { char c; if (car!= '.') { scanf("%c", &c); print_rev(c); printf("%c", car); else return;

Stack Codice... main(void) {... print_rev(k); void print_rev(char car); { if (car!= '.') {... print_rev(c); printf("%c", car); main S.O. else return; Standard Input: "uno."

Stack Codice print_rev main car 'u' S.O.... main(void) {... print_rev(getchar()); print_rev(k); void print_rev(char car); { if (car!= '.') {... print_rev(getchar()); print_rev(c); printf("%c", putchar(car); car); else return; Standard Input: "uno."

Stack Codice print_rev print_rev main car car 'n' 'u' int... f(int a, int b) {static main(void) int X=0; if { (!(a b))... return 1; else print_rev(getchar()); print_rev(k); return X=f(a-2,b-1) + X; void print_rev(char car); { if (car!= '.') main() {... { print_rev(getchar()); printf("%d\n", print_rev(c); f(4,2)); printf("%c", putchar(car); car); else return; S.O. Standard Input: "uno."

Stack Codice print_rev print_rev print_rev main car car car 'o' 'n' 'u' int... f(int a, int b) {static main(void) int X=0; if { (!(a b))... return 1; else print_rev(getchar()); print_rev(k); return X=f(a-2,b-1) + X; void print_rev(char car); { if (car!= '.') main() {... { print_rev(getchar()); printf("%d\n", print_rev(c); f(4,2)); printf("%c", putchar(car); car); else return; S.O. Standard Input: "uno."

print_rev print_rev print_rev print_rev main car car car car '.' 'o' 'n' 'u' Stack Codice int... f(int a, int b) {static main(void) int X=0; if { (!(a b))... return 1; else print_rev(getchar()); print_rev(k); return X=f(a-2,b-1) + X; void print_rev(char car); { if (car!= '.') main() {... { print_rev(getchar()); printf("%d\n", print_rev(c); f(4,2)); printf("%c", putchar(car); car); else return; S.O. Standard Input: "uno."

print_rev print_rev print_rev print_rev main car car car car '.' 'o' 'n' 'u' Stack Codice int... f(int a, int b) {static main(void) int X=0; if { (!(a b))... return 1; else print_rev(getchar()); print_rev(k); return X=f(a-2,b-1) + X; void print_rev(char car); { if (car!= '.') main() {... { print_rev(getchar()); printf("%d\n", print_rev(c); f(4,2)); printf("%c", putchar(car); car); else return; S.O. Standard Input: "uno."

Stack Codice print_rev print_rev print_rev main car car car 'o' 'n' 'u' int... f(int a, int b) {static main(void) int X=0; if { (!(a b))... return 1; else print_rev(getchar()); print_rev(k); return X=f(a-2,b-1) + X; void print_rev(char car); { if (car!= '.') main() {... { print_rev(getchar()); printf("%d\n", print_rev(c); f(4,2)); printf("%c", putchar(car); car); else return; S.O. Standard output: "o" Standard Input: "uno."

Stack Codice print_rev print_rev main car car 'n' 'u' int... f(int a, int b) {static main(void) int X=0; if { (!(a b))... return 1; else print_rev(getchar()); print_rev(k); return X=f(a-2,b-1) + X; void print_rev(char car); { if (car!= '.') main() {... { print_rev(getchar()); printf("%d\n", print_rev(c); f(4,2)); printf("%c", putchar(car); car); else return; S.O. Standard output: "on" Standard Input: "uno."

Stack Codice print_rev main car 'u' int... f(int a, int b) {static main(void) int X=0; if { (!(a b))... return 1; else print_rev(getchar()); print_rev(k); return X=f(a-2,b-1) + X; void print_rev(char car); { if (car!= '.') main() {... { print_rev(getchar()); printf("%d\n", print_rev(c); f(4,2)); printf("%c", putchar(car); car); else return; S.O. Standard output: "onu" Standard Input: "uno."

Stack Codice main int... f(int a, int b) {static main(void) int X=0; if { (!(a b))... return 1; else print_rev(getchar()); print_rev(k); return X=f(a-2,b-1) + X; void print_rev(char car); { if (car!= '.') main() {... { print_rev(getchar()); printf("%d\n", print_rev(c); f(4,2)); printf("%c", putchar(car); car); else return; S.O. Standard output: "onu" Standard Input: "uno."