Pagina 2 di 4

Re: [C] help ricorsione

Inviato: mercoledì 26 giugno 2013, 22:09
da TuxDroid1
Lo stack del processore supponiamo cresca in altezza. La chiamata fact(3) produrrà la seguente sequenza:

Codice: Seleziona tutto

fact(3)

Codice: Seleziona tutto

fact(2)
fact(3)

Codice: Seleziona tutto

fact(1)
fact(2)
fact(3)
Abbiamo incontrato il famoso n<=1 . Comincia la ricomposizione!

Codice: Seleziona tutto

pop(top(stack)) = 1;  
return n*fact(n-1);   prende il valore di 1. 


Stack attuale:
fact(2)  <---------- ora si riprende l'esecuzione di questa chiamata, prima interrotta! 
fact(3)

Codice: Seleziona tutto

pop(top(stack)) = 2
return n*fact(n-1);   prende il valore di 1*2. 


Stack attuale:
fact(3)  <---------- ora si riprende l'esecuzione di questa chiamata, prima interrotta! 

Codice: Seleziona tutto

pop(top(stack)) = 3
return n*fact(n-1);   prende il valore di 1*2*3. 


Stack attuale:

1*2*3 è quello che viene restituito al chiamante, ovvero al main!

Per completezza e formalismo:
Call stack , Ricorsione, LIFO

Re: [C] help ricorsione

Inviato: mercoledì 26 giugno 2013, 22:13
da gila75
Si andrea, ho visto solo dopo...leggo con cura domani e faccio prove...a quest'ora, non concluderei nulla...grazie

Ma domanda: non è che magari mi sto facendo troppe pippe mentali io su come e dove e quando ricompone il tutto?
Forse non è più un problema che riguarderebbe più l'assembly?
Piccolo OT per fare un paragone:
Se io programmo un pic in assembler, mi devo preoccupare di tutto, salvataggio regisro status, accumulatore w ecc... prima di eseguire un interrupt, mentre col c (presumo, visto che usavo l'assembly), no
fa tutto lui...oppure moltiplicazioni che sforano gli 8 bit, col C non devi impazzire con routine matematiche e tante altre cose ancora.

Allora: non è che mi sto addentrando in una cosa che magari (per il momento ) non è così fondamentale?
Dico cio', dopo quello che ho visto postato da Tux, stack e quant'altro.
é solo un dubbio che mi è venuto ora :)

E magari direte voi...Gila ma vattelo a prendere........:) :) tutto sto casino poi ritratti??????
Avete ragione :)

Re: [C] help ricorsione

Inviato: mercoledì 26 giugno 2013, 22:14
da TuxDroid1
Spero che l'esempio che ti ho scritto sopra riesca a chiarirti un minimo.... Intanto ti dico che:
if (n<=1)
return 1;
diciamo: se n è uguale o minore 1 ritorna (e quindi esce dalla funzione) 1 al main. Giusto fin qui?
E allora, come dici giustamente tu, come piffero si ricombiano tutte le chiamate?
è quello il mio dilemma!!!
Con return 1, io esco dalla funzione.
Quando fai return 1 stai svegliando la vecchia chiamata ricorsiva! Qui bisogna scomodare di nuovo il processore e i suoi registri...

fact(3) invoca fact(2). fact(2) avrà in una qualche parte del registro a lei dedicata l'informazione del dove ritornare quando termina. Chi è il chiamante? fact(3). Quindi a chi restituisce il controllo quando terminerà? A fact(3), non al main! Analogamente: fact(1) è invocata da fact(2). Quando termina il controllo ritorna a a fact(2), non al main!
Ogni funzione conosce solo l'indirizzo di ritorno del chiamante, quindi il main non sanno manco chi è! L'unico che ha come indirizzo di ritorno il main è fact(3), e quando termina effettivamente ha già ricombinato il risultato come ti ho mostrato sopra... Perdona se ho descritto il fenomeno in maniera mostruosa, ma credo che violare un attimo i formalismi sia istruttivo per farti capire "terra terra" come funziona :)

Re: [C] help ricorsione

Inviato: mercoledì 26 giugno 2013, 22:22
da gila75
Quando fai return 1 stai svegliando la vecchia chiamata ricorsiva! Qui bisogna scomodare di nuovo il processore e i suoi registri...

fact(3) invoca fact(2). fact(2) avrà in una qualche parte del registro a lei dedicata l'informazione del dove ritornare quando termina. Chi è il chiamante? fact(3). Quindi a chi restituisce il controllo quando terminerà? A fact(3), non al main! Analogamente: fact(1) è invocata da fact(2). Quando termina il controllo ritorna a a fact(2), non al main!
Ogni funzione conosce solo l'indirizzo di ritorno del chiamante, quindi il main non sanno manco chi è! L'unico che ha come indirizzo di ritorno il main è fact(3), e quando termina effettivamente ha già ricombinato il risultato come ti ho mostrato sopra... Perdona se ho descritto il fenomeno in maniera mostruosa, ma credo che violare un attimo i formalismi sia istruttivo per farti capire "terra terra" come funziona :)
GRANDE TUX....bingo!!!

così è chiaro... chi chiama chi....!!!!
Molto chiaro!!!
Grazie!!

Re: [C] help ricorsione

Inviato: mercoledì 26 giugno 2013, 22:24
da TuxDroid1
Ohhh! :D Sono felice di averti chiarito un po la situazione! :) Fai conto che ogni chiamata ricorsiva "copre" la precedente, e quando termina una, si ritorna a quella precedente che è sospesa. Quindi al main si ritorna solo dopo che sono ritornate TUTTE le chiamate ricorsive! :D

Quando una funzione ricorsiva è progettata male, non si entrerà mai in quel return 1, continuando le espansioni all'infinito! E' per questo che va in loop! :)

Re: [C] help ricorsione

Inviato: mercoledì 26 giugno 2013, 22:26
da gila75
Di fatto allora, anche se in modo un po' improrio, non ci sono andato molto lontano nel dire che era chiamate nidificate...ok...passami il termine, ma grossolanamente è così, no?

Re: [C] help ricorsione

Inviato: mercoledì 26 giugno 2013, 22:30
da TuxDroid1
Si, e non è nemmeno tanto improprio definirle chiamate nidificate. Puoi pensarla come una sequenza di blocchi in un linguaggio con scoping statico: ogni blocco piazza un frame sullo stack, finchè quel blocco non finisce, il frame resta li dov'è, e solo quando un frame ritorna al chiamante si comincia a poppare dalla pila tutti i "vecchi" frame. Ovviamente al frame in cima alla pila poco importa di chi ci sta a 4 posizioni più in basso, il suo piccolo compito è quello di calcolare qualcosa e passarlo a chi sta sotto di lui. Tutto il resto... non sono affar suoi! XD

Re: [C] help ricorsione

Inviato: mercoledì 26 giugno 2013, 23:47
da eaghezzi
imho
dopo anni di programmazione ho ancora qualche difficoltà a scrivere procedure ricorsive credo che sia naturale ... non è un modo 'umano' di pensare.

per semplificarti la vita visualizza e immagina ogni chiamata alla funzione ricorsiva come la chiamata ad un altra funzione con un progressivo
nel tuo esempio

Codice: Seleziona tutto

fact(3)
...fact(x).0
...if(x)
.....fact(x).1
........fact(x).2
.............fact(x).3
così forse è più facile capire che ogni chiamata ricorsiva è come una chiamata normale ad un'altra funzione e l'intero ambiente rimane congelato nell'attesa del ritorno della funzione chiamata

non sempre è possibile convertire la ricorsione in cicli ci sono delle regole ben precise.

ti faccio un ultimo esempio senza la ricorsione sarebbe quasi impossibile parsare un documento html e creare il dom, ho lavorato parecchio sull'argomento
pensa che una semplice pagina html può arrivare ad un centinaio di livelli di ricorsione.
prosegui così sei sulla strada giusta.

Re: [C] help ricorsione

Inviato: giovedì 27 giugno 2013, 1:13
da Vincenzo1968
Si può simulare il comportamento del compilatore utilizzando uno stack esplicito e l'istruzione goto:

Codice: Seleziona tutto

#include <stdio.h>

/*
unsigned int fact(int n)     
{
	if ( n <= 1 )
		return 1;
	else
	{
		return n * fact( n-1 );
	}       
}
*/ 

unsigned int fact(int n)
{
	int stack[1024];
	int top = -1;
	int accumulator = 1;

	if ( n == 0 )
		return 1;
	
	printf("PUSH n: %d\n", n);
	stack[++top] = n;
	
	beginning:
	if (n <= 1)
	{
		printf("Raggiunto il caso base n = 1\n");
		
		while ( top >= 0 )
		{
			n = stack[top--];
			printf("POP %d\n", n);
			printf("RETURN %d * %d = %d\n", accumulator, n, accumulator * n);			
			accumulator *= n;
		}

		printf("RETURN %d\n", accumulator);
		return accumulator;
	}
	else
	{
		printf("PUSH n - 1: %d\n", n - 1);	
		n -= 1;	
		stack[++top] = n;
		goto beginning;
	}	
}    
      
int main (void)
{
	int x = 3;
	
	printf("%d! = %u\n", x, fact(x));
	
    return 0;
}
Output:

Codice: Seleziona tutto

$ gcc -Wall -W -O2 fact.c -o fact
$ ./fact
PUSH n: 3
PUSH n - 1: 2
PUSH n - 1: 1
Raggiunto il caso base n = 1
POP 1
RETURN 1 * 1 = 1
POP 2
RETURN 1 * 2 = 2
POP 3
RETURN 2 * 3 = 6
RETURN 6
3! = 6

Re: [C] help ricorsione

Inviato: giovedì 27 giugno 2013, 1:16
da Vincenzo1968
TuxDroid1 [url=http://forum.ubuntu-it.org/viewtopic.php?p=4413444#p4413444][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:Ohhh! :D Sono felice di averti chiarito un po la situazione! :) Fai conto che ogni chiamata ricorsiva "copre" la precedente, e quando termina una, si ritorna a quella precedente che è sospesa. Quindi al main si ritorna solo dopo che sono ritornate TUTTE le chiamate ricorsive! :D

Quando una funzione ricorsiva è progettata male, non si entrerà mai in quel return 1, continuando le espansioni all'infinito! E' per questo che va in loop! :)
In realtà non prosegue mai all'infinito. Ad un certo punto il programma termina(va in crash) perché viene esaurito lo stack di sistema.

Re: [C] help ricorsione

Inviato: giovedì 27 giugno 2013, 8:53
da TuxDroid1
Vincenzo1968 [url=http://forum.ubuntu-it.org/viewtopic.php?p=4413531#p4413531][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto: In realtà non prosegue mai all'infinito. Ad un certo punto il programma termina(va in crash) perché viene esaurito lo stack di sistema.
Si hai ragione, è stata una vista, grazie per la correzione :)
Gila75[url=http://forum.ubuntu-it.org/viewtopic.php?p=4413531#p4413531][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:Ma domanda: non è che magari mi sto facendo troppe pippe mentali io su come e dove e quando ricompone il tutto?
Forse non è più un problema che riguarderebbe più l'assembly?
E' quello che cercavo di dirti ieri sera...Non è una nozione di fondamentale importanza per capire la ricorsione. Di certo è utile conoscere queste implementazioni, ma questo tipo di informazioni esulano dalla programmazione "fine a se stessa". Ecco perchè il manuale del C non spiega come "funziona sotto al cofano". E' un po come se ti dovesse spiegare come si comporta il processore con tutti i linguaggi che incontra, dal condizionale ai cicli... Quelle sono astrazioni e per utilizzarle in maniera corretta non è necessario aver studiare l'architettura del sistema. :ciao:

Re: [C] help ricorsione

Inviato: giovedì 27 giugno 2013, 17:50
da M_A_W_ 1968
Sfortunatamente il mio tempo libero in questo periodo tende a zero, e sono costretto a rinunciare ai piaceri del forum.
Scorrendo il thread ho notato, nel solito contesto di buona volontà e generale correttezza, alcune affermazioni parzialmente corrette, altre anche errate, ma purtroppo in questo momento non ho il tempo di emendarle. Mi limito a fornire due telegrafici consigli validi per l'OP, e non solo.

1) Gila, ricordati sempre da dove vieni. Il miglior amico dell'uomo è il cane, ma il miglior amico del programmatore (embedded) è il debugger. La sua funzione non è solo quella di cacciare insetti, suggerita dall'ingannevole onomastica, ma anche e soprattutto quella di rappresentare una connessione immediata con la semantica operazionale del codice. In altri termini, permette di seguire ogni passo eseguito, con il relativo stato della memoria ossia delle variabili coinvolte, dello stack, e quant'altro. Prendere la sanissima abitudine di saper leggere ed eseguire in step mode il codice assembly prodotto,. o quantomeno di seguire a runtime il proprio codice entro uno step debugger HLL non ha prezzo ed è in assoluto il più vitale supporto didattico per un programmatore a qualsiasi livello.

2) Un quarto di secolo fa ho iniziato, per studio e per mestiere, a leggere sorgenti scritti da professionisti e pagati fior di quattrini, con tanto di contratti di non disclosure: librerie, applicazioni, compilatori, interpreti, framework, interi sistemi operativi. In questo lunghissimo periodo di tempo, nei milioni di linee di codice letti, avrò trovato implementazioni realmente ricorsive al più una dozzina di volte, se ovviamente escludiamo linguaggi puramente funzionali e loro parenti, pesantissimamente basati su implementazioni ad altissima efficienza di costrutti di tail recursion.
Nel mondo reale la ricorsione è una necessità rarissima, a causa del suo ingordo consumo di risorse e della notevole inefficienza generale rispetto all'interazione. D'altro canto, l'uso di banali cicli con numero di iterazioni noto solo a runtime è consentito dai costrutti di praticamente tutti i linguaggi più diffusi, con le più varie forme di gestione della condizione di permanenza (o terminazione).

3) In soldoni, esistono dei fan accaniti della ricorsione in ambito accademico e tra i laureati in scienze formali in genere (logici, matematici, informatici teorici, e altri colleghi del sottoscritto), perché in effetti le implementazioni sono praticamente la fotocopia della relativa espressione formale dell'algoritmo in termini induttivi. Altrettanto banalmente, la mia lunga esperienza didattica in azienda suggerisce che programmatori con diverso background (dagli elettronici ai fisici, dai biologi ai medici, ai practitioner di più varia estrazione) trovano sistematicamente incomprensibile, innaturale e controintuitivo l'uso di quella forma, riuscendo a concepire in modo molto più efficiente e fluido la controparte iterativa, anche se di complessità superiore. Dato che la programmazione è sempre il risultato dell'interazione tra uomo e linguaggio, vale in assoluto il principio ingegneristico di praticare sempre e solo la strada che si conosce e si comprende meglio. Ciò non toglie, ovviamente, valore a quanto già espresso al punto 1).

MI fermo qui, solo per limiti di tempo. Come sempre, resto a disposizione per ogni sorta di approfondimento e giustificazione teorica o ingegneristica di quanto richiamato.

Re: [C] help ricorsione

Inviato: giovedì 27 giugno 2013, 18:13
da eaghezzi
Nel mondo reale la ricorsione è una necessità rarissima, a causa del suo ingordo consumo di risorse e della notevole inefficienza generale rispetto all'interazione. D'altro canto, l'uso di banali cicli con numero di iterazioni noto solo a runtime è consentito dai costrutti di praticamente tutti i linguaggi più diffusi, con le più varie forme di gestione della condizione di permanenza (o terminazione).

non so quali sorgenti tu abbia studiato
quando hai finito di erurdirci regalati una pausa e
prova a guardare banalmente i sorgenti di firefox ci sono almeno venti implementazioni ricorsive e non per scopi accademici
un ' altro esempio ben noto è l'implementazione di jquery è fondamentalmente basata sulla ricorsione.
la maggior parte dei db nosql si basa sulla ricorsione e strutture ad albero.
Quando esprimi delle opinioni ricordati che puoi influenzare chi ne sa meno di cerca di essere obbiettivo

Re: [C] help ricorsione

Inviato: giovedì 27 giugno 2013, 18:50
da M_A_W_ 1968
eaghezzi [url=http://forum.ubuntu-it.org/viewtopic.php?p=4413842#p4413842][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto: prova a guardare banalmente i sorgenti di firefox ci sono almeno venti implementazioni ricorsive e non per scopi accademici
un ' altro esempio ben noto è l'implementazione di jquery è fondamentalmente basata sulla ricorsione.
la maggior parte dei db nosql si basa sulla ricorsione e strutture ad albero.
1) Hai citato tre casi, sono solo alcune centinaia di migliaia di LOC. Fossero anche due o tre milioni, rimane una goccia nell'oceano. Sei proprio sicuro che la base statistica del codice che conosci sia realmente sufficiente a trarre conclusioni induttivamente valide e ben fondate? Io parlo di milioni di LOC afferenti al codice più vario: librerie di calcolo e di comunicazione, compilatori, RTOS. Senza dimenticare il fattore di scala fondamentale: per ogni riga di codice destinata a PC e affini ne esistono circa trecento destinate ad altre piattaforme. Quando codice embedded hai visto in vita tua? E quante implementazioni induttive pensi di trovare su una piattaforma a 14 bit di program word che neppure supporta lo stack in hardware? Quando si parla di "codice" a 360° bisogna avere ben chiari in mente questi fatti, non solo il piccolo mondo dei PC. Nella statistica rientrano anche 30GLoc di COBOL ancora funzionanti, tanto per dire.
La maggior parte del codice che viene prodotto al mondo NON è destinata ad un PC X86. Dunque il tuo esempio è fuorviante e, questo sì, ben poco obiettivo.

2) Non mi pare in ogni caso che firefox o (peggio mi sento) jquery brillino per prestazioni, in generale. Ma questo è un altro paio di maniche.

3) L'OP viene dalla programmazione dei PIC, e ci orbita ancora attorno. Quando si risponde a qualcuno come lui, si deve fare bene mente locale ed impartirgli consigli spendibili sui due fronti, cercando semmai di tracciare una distinzione tra quello che può permettersi su una piattaforma anabolizzata come il PC e piattaforme tiny, ma pur sempre supportate da cross compiler C.

4) Le polemiche mi fanno vento agli alluci. Ma la prossima volta che interagisci col sottoscritto, metti da parte sarcasmo e facezie. Con ogni probabilità, sono davvero in grado di erudirti per mesi, restando al solo mondo IT. E richiamare all'obiettività un logico matematico è una battuta da colorado café.

Re: [C] help ricorsione

Inviato: venerdì 28 giugno 2013, 14:28
da Vincenzo1968
Un esempio nel quale si mostra la praticità della ricorsione:

Codice: Seleziona tutto

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void combinations (int v[], int start, int n, int k, int maxk)
{
	int i;
	
	if (k > maxk)
	{
		for (i = 1; i <= maxk; i++)
			printf ("%i ", v[i]);
		printf ("\n");
		return;
	}

	for (i = start; i <= n; i++)
	{
		v[k] = i;
		combinations (v, i+1, n, k+1, maxk);
	}
}

int main (int argc, char *argv[])
{
	clock_t c_start, c_end;
	double TempoImpiegato;  
	int n, k;
	int *v;        
	
	if (argc != 3)
	{
		printf ("Uso: %s n k\n", argv[0]);
		exit (1);
	}
	n = atoi (argv[1]);
	k = atoi (argv[2]);
	
	v = (int*)calloc(n + 1, sizeof(int));
	if ( !v )
	{
		printf("Errore: memoria insufficiente.\n");
		return -1;		
	}
        
	c_start = clock();
	
	combinations (v, 1, n, 1, k);
        
	c_end = clock();
	TempoImpiegato = (double)(c_end - c_start) / CLOCKS_PER_SEC;
	printf("Tempo impiegato -> %5.5f secondi\n\n", TempoImpiegato);
	
	free(v);
	
	return 0;
}
Immagine
Immagine

La funzione ricorsiva combinations calcola, in modo compatto(poche righe di codice) ed efficiente, le combinazioni di un insieme di numeri.

Re: [C] help ricorsione

Inviato: venerdì 28 giugno 2013, 16:35
da Vincenzo1968
Una versione iterativa per la generazione delle combinazioni(algoritmo tratto da The Art of Computer Programming di Donald E. Knuth):

Codice: Seleziona tutto

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define true 1
#define false 0

typedef  int * ksubset;
   
/* Calcola il coefficiente binomiale "n sopra r" */
int BinCoef(int n, int r)
{
	int i, b;
	
	if ( (r < 0) || (n < r) )
		return 0;
		
	if ( (2 * r) > n )
		r = n - r;
	b = 1;
	if (r > 0)
		for(i = 0; i <= (r - 1); i++)
			b = (b * (n - i))/(i + 1);
			
	return b;
}

void kSubsetLexUnrank(int r, ksubset T, int n, int k)
{
	int x,i,y;
	
	x = 1;
	for(i = 1; i <= k; i++)
	{
		y = BinCoef(n - x, k - i);
		while (y <= r)
		{
			r = r - y;
			x = x + 1;
			y = BinCoef(n - x, k - i);
		}
		T[i] = x;
		x = x + 1;
	}
}

int main(int argc, char *argv[])
{
	int n, k;
	int NN, r, j;
	ksubset T;
	clock_t c_start, c_end;
	double TempoImpiegato;   
	
	if(argc != 3)
	{
		fprintf(stderr,"Uso: %s n k\n", argv[0]);
		return -1;
	}
	n = atoi(argv[1]);
	k = atoi(argv[2]);  
	if (k < 0)
	{
		fprintf(stderr,"k deve essere > 0\n");
		fprintf(stderr,"Uso: %s n k\n", argv[0]);
		return -1;
	}
	if (k > n)
	{
		fprintf(stderr,"k deve essere <= n\n");
		fprintf(stderr,"Uso: %s n k\n", argv[0]);
		return -1;
	}

	T = (int *)calloc(k + 1, sizeof(int)); 
	if ( !T )
	{
		printf("Errore: memoria insufficiente.\n");
		return -1;
	}
	NN = BinCoef(n, k);
    
    printf("n = %d k = %d Numero combinazioni = %d\n\n", n, k, NN);
    
    c_start = clock();
    for(r = 0; r < NN; r++)
    {
		kSubsetLexUnrank(r, T, n, k);
		for (j = 1; j <= k; j++)
			printf(" %d",T[j]);
		printf("\n");
	}
	
	c_end = clock();
	TempoImpiegato = (double)(c_end - c_start) / CLOCKS_PER_SEC;
	printf("Tempo impiegato -> %5.5f secondi\n\n", TempoImpiegato); 
	
	free(T);
		
	return 0;
}
Immagine

Re: [C] help ricorsione

Inviato: venerdì 28 giugno 2013, 16:41
da Vincenzo1968
Un'altra versione iterativa, più efficiente(algoritmo tratto sempre dal TAOCP):

Codice: Seleziona tutto

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define true 1
#define false 0

typedef  int * ksubset; 

/* Calcola il coefficiente binomiale "n sopra r" */
int BinCoef(int n, int r)
{
	int i, b;
	
	if ( (r < 0) || (n < r) )
		return 0;
		
	if ( (2 * r) > n )
		r = n - r;
	b = 1;
	if (r > 0)
		for(i = 0; i <= (r - 1); i++)
			b = (b * (n - i))/(i + 1);
			
	return b;
}

void kSubsetLexSuccessor(ksubset T, int * flag, int n, int k, ksubset U)
{
	int i, j;
	
	(*flag) = true;
	
	for(i = 1; i <= k; i++)
		U[i] = T[i];
	i = k;
	
	while ( (i >= 1) && (T[i] == (n - k + i)) )
		i = i - 1;
	if (i == 0) 
		(*flag) = false;
	else
	{
		for (j = i; j <= k; j++)
			U[j] = T[i] + 1 + j - i;
		for (j = 1; j <= k; j++)
			T[j] = U[j];
	}
}

int main(int argc, char *argv[])
{
	int n, k, j;
	int flag;
	int NN;
	ksubset T;
	ksubset U;
	clock_t c_start, c_end;
	double TempoImpiegato;   
	
	if(argc != 3)
	{
		fprintf(stderr,"Uso: %s n k\n", argv[0]);
		return -1;
	}
	n = atoi(argv[1]);
	k = atoi(argv[2]);  
	if (k < 0)
	{
		fprintf(stderr,"k deve essere > 0\n");
		fprintf(stderr,"Uso: %s n k\n", argv[0]);
		return -1;
	}
	if (k > n)
	{
		fprintf(stderr,"k deve essere <= n\n");
		fprintf(stderr,"Uso: %s n k\n", argv[0]);
		return -1;
	}
	
	T = (int *)calloc(k + 1, sizeof(int)); 
	if ( !T )
	{
		printf("Errore: memoria insufficiente.\n");
		return -1;
	}	
	
	U = (int *)calloc(k + 1, sizeof(int)); 
	if ( !U )
	{
		printf("Errore: memoria insufficiente.\n");
		free(T);
		return -1;
	}	
	
	NN = BinCoef(n, k);
    
    printf("n = %d k = %d Numero combibazioni = %d\n\n", n, k, NN);
    
	c_start = clock();
	for (j = 1; j <= k; j++)
		T[j] = j;
	flag = true;
	while (flag)
	{
		for (j = 1; j <= k; j++)
			printf(" %d", T[j]);
		printf("\n");
		kSubsetLexSuccessor(T, &flag, n , k, U);
	}
	
	c_end = clock();
	TempoImpiegato = (double)(c_end - c_start) / CLOCKS_PER_SEC;
	printf("Tempo impiegato -> %5.5f secondi\n\n", TempoImpiegato);   	
	
	free(T);
	free(U);
		
	return 0;
}
Immagine

Re: [C] help ricorsione

Inviato: venerdì 28 giugno 2013, 20:06
da gila75
Grazie a tutti ragazzi!!
MAW: il debugger, è vero è fondamentale, ma credo che sia ancora un po' presto per me, anche se non è detto che non ne scarichi uno e ci studi sopra.
Vincenzo: interessanti i listati. Ora non sono a casa e non posso provarli\studiarli, ma appena posso...
Domanda: ma che profondità ha mediamente uno stack?
Ho fatto un programmino in modo ricorsivo che somma i numeri da 1 a n
n=5
1+2+3+4+5...
Dando n=1000000, il progrmma crasha, credo proprio che lo stack sia esaurito no?

Re: [C] help ricorsione

Inviato: venerdì 28 giugno 2013, 20:37
da Vincenzo1968
Solitamente lo stack di sistema è impostato alla dimensione di 8 MB.
Puoi verificarlo col comando ulimit:

Codice: Seleziona tutto

ulimit -s
Da me restituisce 8192 Kb.

o:

Codice: Seleziona tutto

ulimit -a
output:

Codice: Seleziona tutto

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 29952
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 29952
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Re: [C] help ricorsione

Inviato: venerdì 28 giugno 2013, 21:19
da TuxDroid1
gila75 ha scritto: il debugger, è vero è fondamentale, ma credo che sia ancora un po' presto per me, anche se non è detto che non ne scarichi uno e ci studi sopra.
Non è mai troppo presto per il debugger! Da noi in università spiegano prima come si usa un debugger, poi come si scrive hello world in C! :) Comunque un debugger dovresti già averlo: gdb :D Provalo, è veramente una manna dal cielo! Poi magari ci sarà tempo per utilizzare un IDE sofisticato con un sacco di funzionalità in più rispetto all'accoppiata gedit+gdb, ma se sei all'inizio il debugger non può che aiutarti a capire come avviene il flusso d'esecuzione del tuo codice :)