Newsgroup: it.comp.lang.c
Titolo: funzioni e ricorsione

Ho implementato la struttura di un albero binario, la procedura di
inserimento dei nodi è ricorsiva:
void input(binalbero *T)
{
   tipoelem a;
   char s;
   printf("Inserire la label del nodo radice: ");
   scanf("%i",&a);
   addbin(a,T);
   printf("\n");
 printf("Per inserire il sottoalbero sinistro del nodo %i",a);
   printf(" premere 's': ");
   scanf("%1s",&s);
   if(s=='s') input(&((*T)->sinistro));
   printf("\n");
   printf("Per inserire il sottoalbero destro del nodo %i",a);
   printf(" premere 's': ");
   scanf("%1s",&s);
   if(s=='s') input(&((*T)->destro));
}
fa uso dell'operatore addbin:
void addbin(tipoelem a,nodo *u)
{
 nodo temp;
   temp=*u;
   *u=(nodo) malloc(sizeof(struct cella));
   (*u)->sinistro=NULL;
   (*u)->destro=NULL;
   (*u)->genitore=temp;
   (*u)->elemento=a;
}
il problema è questo: dopo la prima chiamata ricorsiva, il contenuto della
variabile "a" non viene salvato, ma la variabile viene posta uguale a zero,
quindi, perdo l'indicazione  del nodo a cui si aggiunge il sottoalbero
destro o sinistro.
Perchè? In Pascal non ho avuto questo problema!
illuminatemi ^___^
Salvatore

"Sasà" ha scritto
: fa uso dell'operatore addbin:
:
: void addbin(tipoelem a,nodo *u)
: {
:  nodo temp;
:    temp=*u;
:    *u=(nodo) malloc(sizeof(struct cella));
:    (*u)->sinistro=NULL;
:    (*u)->destro=NULL;
:    (*u)->genitore=temp;
:    (*u)->elemento=a;
: }
:
: illuminatemi ^___^
: Salvatore
:
Sigh. Prova a togliere il cast prima di malloc e poi correggi il resto
fino a che il compilatore non ti da piu` nessun errore...
ciao
Massimo

 fino a che il compilatore non ti da piu` nessun errore...
Ehm, ma il compilatore non mi da nessun errore...
...il programma viene eseguito correttamente tranne per la perdita
dell'informazione relativa al nodo al ritorno della chiamata ricorsiva.
Ho provato a togliere il cast, ma non è cambiato nulla.
Ciao Salvatore

"Sasà" ha scritto
:
: >
: > Sigh. Prova a togliere il cast prima di malloc e poi correggi il resto
: > fino a che il compilatore non ti da piu` nessun errore...
:
: Ehm, ma il compilatore non mi da nessun errore...
: ...il programma viene eseguito correttamente tranne per la perdita
: dell'informazione relativa al nodo al ritorno della chiamata ricorsiva.
:
: Ho provato a togliere il cast, ma non è cambiato nulla.
:
Il problema del cast sta nel fatto che sono giorni che su questo
NG spiegano che usarlo davanti ad una malloc puo` avere l'effetto
di nascondere degli warning da parte del compilatore. Per cui in
un codice che fa largo uso di tipi definiti dall'utente, con
dichiarazione non visibile nel post, il primo errore che salta
agli occhi e` proprio quello.
: void input(binalbero *T)
: {
:    tipoelem a;
:    char s;
:
:    printf("Inserire la label del nodo radice: ");
:    scanf("%i",&a);
:    addbin(a,T);
:    printf("\n");
:  printf("Per inserire il sottoalbero sinistro del nodo %i",a);
:    printf(" premere 's': ");
:    scanf("%1s",&s);
:    if(s=='s') input(&((*T)->sinistro));
: il problema è questo: dopo la prima chiamata ricorsiva, il contenuto della
: variabile "a" non viene salvato, ma la variabile viene posta uguale a
zero,
: quindi, perdo l'indicazione  del nodo a cui si aggiunge il sottoalbero
: destro o sinistro.
Tieni conto che ogni volta che chiami una funzione, ricorsiva o meno,
di ogni variabile locale viene creata una nuova copia, che e` l'unica
a cui puoi accedere dalla funzione, per cui non e` vero che non viene
salvata e viene posta uguale a zero. Sta sullo stack, un po' piu` su.
Ritroverai il valore inserito quando la funzione ricorsiva termina la
sua esecuzione.
Per capirci: se tu scrivessi per esteso, a due livelli, la funzione
input otterresti piu` o meno
void input(binalbero *T)
{
  tipoelem a;
  char s;
  printf("Inserire la label del nodo radice: ");
  scanf("%i",&a);
  addbin(a,T);
  printf("\n");
  printf("Per inserire il sottoalbero sinistro del nodo %i",a);
  printf(" premere 's': ");
  scanf("%1s",&s);
  if(s=='s')
  {
    tipoelem a;
    char s;
    printf("Inserire la label del nodo radice: ");
    scanf("%i",&a);
...
In cui la variabile a zero (per caso, perche` tu non la inizializzi)
e` quella interna.
Invece se ti serve il valore 'esterno' devi passarlo nella lista
dei parametri. Qualcosa tipo:
void input( binalbero *T, int label_genitore )
{
ciao
Massimo

 sua esecuzione.
Era esattamente quello che mi aspettavo, ma in esecuzione, la funzione si
comporta diversamente.
Cmq, il problema non è nelle chiamate ricorsive!
Ho notato che la perdita del contenuto della variabile "a" avviene qui:
void input(binalbero *T)
{
   tipoelem a;
   char s;
   printf("Inserire la label del nodo radice: ");
   scanf("%i",&a);
   addbin(a,T);
   printf("\n");
 printf("Per inserire il sottoalbero sinistro del nodo %i",a);
   printf(" premere 's': \n");
   scanf("%1s",&s);
dopo la scanf perdo il contenuto di "a", perchè?
L'ho verificato, infatti, scrivendo:
scanf("%c%c",&s,&s);
la funzione si comporta come mi aspettavo.
Non capisco però, la necessità di dover leggere con la scanf, 2 caratteri,
di cui il primo se non erro è il new line.
Mi spiegate cosa c'è che non va? Cosa devo utilizzare per poter assumere in
input un carattere?
Ciao e grazie
Salvatore