[C] Dubbio esercizio funzione ricorsiva
Buonasera a tutti!
Ho un dubbio sullo svolgimento di questo esercizio:
"Si scriva in C una funzione ricorsiva che legge in input una sequenza di interi che termina quando viene immesso zero (che non fa parte della sequenza), e restituisce true se il prodotto di tutti gli elementi letti è un intero positivo, altrimenti restituisce false, senza utilizzare la moltiplicazione".
Io ho fatto il seguente codice
La mia idea è quella di contare i numeri negativi che appaiono nella sequenza e poi verificare la sua parità.
Però non funziona
Ho un dubbio sullo svolgimento di questo esercizio:
"Si scriva in C una funzione ricorsiva che legge in input una sequenza di interi che termina quando viene immesso zero (che non fa parte della sequenza), e restituisce true se il prodotto di tutti gli elementi letti è un intero positivo, altrimenti restituisce false, senza utilizzare la moltiplicazione".
Io ho fatto il seguente codice
#include <stdio.h> typedef enum {false, true} boolean; boolean ric(){ int neg=0,m; scanf("%d",&m); if(m!=0){ if(m<0) neg=1+ric(); else neg=ric(); } if((neg%2==0)) return true; else return false; }
La mia idea è quella di contare i numeri negativi che appaiono nella sequenza e poi verificare la sua parità.
Però non funziona

Risposte
Ci sono varie cose che mi sembrano sbagliate o fatte male.
Innanzitutto, o usi vero e falso o usi gli interi. Quello che fai ridefinisce vero e falso come zero e uno [che è quello che sono in pratica, ma non concettualmente] e li usi per fare delle somme, il che è cattiva pratica.
Se vuoi fare le cose con vero e falso, allora usa [inline]not neg[/inline] o [inline]!neg[/inline] per cambiare tra uno e l'altro; se vuoi usare i numeri allora liberati di [inline]true[/inline] e [inline]false[/inline] che fanno solo confusione.
Un'altra cosa che magari non è sbagliata ma che è brutta da vedere è che restituisci sempre [inline]0[/inline] o [inline]1[/inline] anche se [inline]neg[/inline] è, per esempio, [inline]5[/inline] [che in realtà non può mai essere].
Fossi in te pulirei il codice prima di cercare dov'è l'errore, che comunque si vede già da qui.
Innanzitutto, o usi vero e falso o usi gli interi. Quello che fai ridefinisce vero e falso come zero e uno [che è quello che sono in pratica, ma non concettualmente] e li usi per fare delle somme, il che è cattiva pratica.
Se vuoi fare le cose con vero e falso, allora usa [inline]not neg[/inline] o [inline]!neg[/inline] per cambiare tra uno e l'altro; se vuoi usare i numeri allora liberati di [inline]true[/inline] e [inline]false[/inline] che fanno solo confusione.
Un'altra cosa che magari non è sbagliata ma che è brutta da vedere è che restituisci sempre [inline]0[/inline] o [inline]1[/inline] anche se [inline]neg[/inline] è, per esempio, [inline]5[/inline] [che in realtà non può mai essere].
Fossi in te pulirei il codice prima di cercare dov'è l'errore, che comunque si vede già da qui.
Interessante la critica al true e false...a lezione abbiam fatto sempre così quando c'è una funzione booleana.
Vedrò di sistemare questa cosa.
Comunque il problema potrebbe essere l'aver inizializzato dalla dichiarazione neg=0?
Forse così è come se ad ogni "giro di ricorsione" azzerassi il tutto
Vedrò di sistemare questa cosa.
Comunque il problema potrebbe essere l'aver inizializzato dalla dichiarazione neg=0?
Forse così è come se ad ogni "giro di ricorsione" azzerassi il tutto
No, il problema è che stai riciclando il caso base per il passo ricorsivo, e lo stai facendo nel modo sbagliato.
Il tuo professore può non essere d'accordo, ma per me [inline]1+boolean[/inline] è alla stregua di un errore. Poi, siamo tutti d'accordo che funziona, ma anche spezzare i differenziali per risolvere ODE "funziona"...
Il tuo professore può non essere d'accordo, ma per me [inline]1+boolean[/inline] è alla stregua di un errore. Poi, siamo tutti d'accordo che funziona, ma anche spezzare i differenziali per risolvere ODE "funziona"...
Io farei qualcosa del genere:
Ovviamente al posto della libreria stdbool puoi utilizzare sia un semplice int che un' enum come quella da te definita.
#include <stdio.h> #include <stdbool.h> bool ric() { int n; scanf("%d", &n); if(n) { return (n > 0) == ric(); } return true; } int main() { if(ric()) { printf("POSITIVO"); } else { printf("NEGATIVO"); } return 0; }
Ovviamente al posto della libreria stdbool puoi utilizzare sia un semplice int che un' enum come quella da te definita.
Ho fatto una cosa simile credo:
Resta il fatto che non capisco dove stava il problema prima...
Ora non mi pare che io abbia cambiato molto; solo il fatto che ho trasportato il controllo della parità all'esterno della ricorsiva
O sbaglio?
int ric(){ int neg=0; int m; scanf("%d",&m); if(m!=0){ if(m<0) neg=1+ric(); else neg=ric(); } return neg; } boolean check(){ int b; b=ric(); if(b%2==0) return true; else return false; }
Resta il fatto che non capisco dove stava il problema prima...
Ora non mi pare che io abbia cambiato molto; solo il fatto che ho trasportato il controllo della parità all'esterno della ricorsiva
O sbaglio?
In realtà non mi sembra tanto simile alla soluzione che ho postato io e inoltre non mi sembra rispetti quella che è la traccia dell'esercizio!
In ogni caso quest'ultimo codice che hai postato funziona perchè la funzione ric() semplicemente ritorna il numero di inserimenti negativi effettuati, mentre la funzione check() controlla se il suddetto valore è pari o dispari.
Per quanto riguarda invece il codice riportato nel post iniziale, magari sarà un mio limite, ma faccio fatica ad individuare una logica precisa... per esempio sei consapevole del fatto che la variabile neg può assumere solo valori compresi nell'intervallo [0;2]?
In ogni caso quest'ultimo codice che hai postato funziona perchè la funzione ric() semplicemente ritorna il numero di inserimenti negativi effettuati, mentre la funzione check() controlla se il suddetto valore è pari o dispari.
Per quanto riguarda invece il codice riportato nel post iniziale, magari sarà un mio limite, ma faccio fatica ad individuare una logica precisa... per esempio sei consapevole del fatto che la variabile neg può assumere solo valori compresi nell'intervallo [0;2]?
Sì, ho fatto due funzioni perché in quella non riesco proprio a capire dov'è il problema...ad esempio quello che mi dici tu su valori più grandi di 2 proprio non capisco dove si inceppa 
Invece così facendo mi son fatto restituire dalla ricorsiva il numero dei negativi inseriti(e in questa mi pare che neg possa assumere valori più grandi di 2), mentre check mi controlla se il totale è pari o dispari
Se è pari allora il risultato del main sarà true dato che il prodotto di tutti gli inseriti sarà positivo, false altrimenti

Invece così facendo mi son fatto restituire dalla ricorsiva il numero dei negativi inseriti(e in questa mi pare che neg possa assumere valori più grandi di 2), mentre check mi controlla se il totale è pari o dispari
Se è pari allora il risultato del main sarà true dato che il prodotto di tutti gli inseriti sarà positivo, false altrimenti
"nick_10":
ad esempio quello che mi dici tu su valori più grandi di 2 proprio non capisco dove si inceppa
All'interno di ogni chiamata ricorsiva la variabile neg vale inizialmente 0 e può essere modificata solo da una delle seguenti assegnazioni:
neg = 1 + ric();
neg = ric();
e poiché ric() può tornare solo 0 e 1, ecco il motivo per cui il range all'interno del quale può variare neg è [0;2].
Per quanto riguarda il codice che ho postato hai capito qual è la logica?
Quindi il problema nel primo codice è che la funzione ricorsiva ritornava true(1) o false(0)?
Per quanto riguarda il tuo codice non capisco il passaggio if(n) e poi il return (n>0)==ric(). La tua logica credo sia diversa dal contare "i segni meno" della sequenza.
Ma il mio metodo è proprio da buttare? Se volessi fare una funzione ricorsiva che mi conti i negativi e poi controlli che la somma sia pari o dispari?
Per quanto riguarda il tuo codice non capisco il passaggio if(n) e poi il return (n>0)==ric(). La tua logica credo sia diversa dal contare "i segni meno" della sequenza.
Ma il mio metodo è proprio da buttare? Se volessi fare una funzione ricorsiva che mi conti i negativi e poi controlli che la somma sia pari o dispari?
Quindi il problema nel primo codice è che la funzione ricorsiva ritornava true(1) o false(0)?
Se lo scopo era quello di contare i vari inserimenti negativi, sì, quello era uno dei problemi.
Per quanto riguarda il tuo codice non capisco il passaggio if(n)...
if(n) coincide con if(n!=0). Mi spiego meglio...
Le condizioni delle istruzioni di controllo (if, while, ...) sono delle espressioni logiche e come tali possono assumere solo due valori: vero (1) e falso (0). Il risultato di un'espressione logica è quindi una quantità booleana.
Tornando ad if(n), essendo la condizione costituita da una variabile intera e dovendo essere valutata come un'espressione logica, quello che avviene è un casting implicito da int a bool. Ebbene le regole di casting da int a bool prevedono che 0 coincide con false e tutti gli altri possibili valori (sia positivi che negativi) con true.
...e poi il return (n>0)==ric(). La tua logica credo sia diversa dal contare "i segni meno" della sequenza.
Consideriamo per esempio la sequenza di inserimenti -5 3 -7 0; risolvendo la ricorsione a ritroso avremo che:
- per n=0 la funzione ritorna 1 (poiché l'if viene saltato);
- per n=-7, valutando l'espressione logica (n>0)==ric(), la funzione ritorna 0==1, ossia 0;
- per n=3 la funzione ritorna 1==0, ossia 0;
- per n=-5 la funzione ritorna 0==0, ossia 1.
In pratica una volta incontrato un valore negativo, l'unico modo affinché la funzioni ritorni nuovamente 1 è quello di incontrare un nuovo valore negativo... e quindi in definitiva il risultato della ricorsione sarà 1 soltanto se il numero di inserimenti negativi è multiplo di 2.
Ma il mio metodo è proprio da buttare? Se volessi fare una funzione ricorsiva che mi conti i negativi e poi controlli che la somma sia pari o dispari?
Se intendi una funzione del tipo bool ric(void), allora la vedo difficile!
@Super squirrel: a dare una soluzione ero capace pure io, ma come vedi non hai risolto granché. Cerca di attenerti al regolamento.
@Nick: la tua idea è buona, devi però implementarla correttamente. Prova a eseguire a voce il tuo codice con la sequenza [inline]1 0[/inline], controlla se ottieni il risultato corretto e in caso contrario cerca di capire dov'è che le cose vanno male e perché.
@Nick: la tua idea è buona, devi però implementarla correttamente. Prova a eseguire a voce il tuo codice con la sequenza [inline]1 0[/inline], controlla se ottieni il risultato corretto e in caso contrario cerca di capire dov'è che le cose vanno male e perché.
Grazie ad entrambi intanto per la pazienza...non sono un tipo facile xD
Comunque rileggendo il mio primo codice ho capito davvero che non ha alcun senso...
Per rifarlo da capo ho pensato ad una cosa del genere
Questa volta dovrebbe andare...più che altro ho giocato sul 1 e -1...non saprei come farlo col true(1) e false che però è "identificato" da 0.
P.s. Invece se posso utilizzare due funzioni potrei tenermi anche il secondo codice che ho pubblicato. O sbaglio?
Comunque rileggendo il mio primo codice ho capito davvero che non ha alcun senso...
Per rifarlo da capo ho pensato ad una cosa del genere
#include <stdio.h> int ric() { int n; scanf("%d", &n); if(n==0) return 1; else{ if(n<0) return -1*ric(); else return 1*ric(); } } int main() { if(ric()==1) printf("TRUE"); else printf("FALSE"); return 0; }
Questa volta dovrebbe andare...più che altro ho giocato sul 1 e -1...non saprei come farlo col true(1) e false che però è "identificato" da 0.
P.s. Invece se posso utilizzare due funzioni potrei tenermi anche il secondo codice che ho pubblicato. O sbaglio?
Stai usando delle moltiplicazioni, quel codice non è accettabile 
Come ti dicevo, basta fare return ric o return not ric.

Come ti dicevo, basta fare return ric o return not ric.
Argh...giusto 
Nel frattempo ci ho riprovato di nuovo. Butto qui solo un'idea dato che ancora non lo provo

Nel frattempo ci ho riprovato di nuovo. Butto qui solo un'idea dato che ancora non lo provo
int ric() { //salto un attimo tutte le dichiarazioni che servono if(n==0) return 0; else{ if(n<0) { neg=1+ric(); if(neg%2==0) return 0; else return -1; } else return ric(); } }
Quello di primo era corretto... ritornava 1 in caso di prodotto positivo e -1 in caso di prodotto negativo (seguendo invece l'indicazione di @Raptorista avresti avuto 1 e 0 al posto di 1 e -1).
Il problema è che se la funzione deve essere del tipo bool ric(void), non c'è modo di tenere il conto degli inserimenti negativi...
il codice che hai postato prima (così come quello da me postato) funziona perché il valore di ritorno della generica chiamata ricorsiva ritorna il "segno" del prodotto fino a quel punto. In pratica, proprio perché non è possibile tenere il conto degli inserimenti negativi attraverso una variabile neg, ci si limita a confrontare il segno del prodotto fino a quel momento con il segno di n nell'attuale chiamata ricorsiva.
"nick_10":
Nel frattempo ci ho riprovato di nuovo. Butto qui solo un'idea dato che ancora non lo provo
Il problema è che se la funzione deve essere del tipo bool ric(void), non c'è modo di tenere il conto degli inserimenti negativi...
il codice che hai postato prima (così come quello da me postato) funziona perché il valore di ritorno della generica chiamata ricorsiva ritorna il "segno" del prodotto fino a quel punto. In pratica, proprio perché non è possibile tenere il conto degli inserimenti negativi attraverso una variabile neg, ci si limita a confrontare il segno del prodotto fino a quel momento con il segno di n nell'attuale chiamata ricorsiva.
Quello di prima non andava bene perché ho usato delle moltiplicazioni...e in questo esercizio non posso utilizzarle.
La bozza che ho scritto come ultima cosa l'ho sistemata e pare vada bene.
La bozza che ho scritto come ultima cosa l'ho sistemata e pare vada bene.
Vabbè io ci rinuncio!

@nick_10: potresti cercare di fare un po' più di attenzione quando qualcuno cerca di aiutarti
Comunque, mi sembra che sei arrivato abbastanza vicino alla soluzione e che ci stia provando. Ti mostro come l'avrei fatto io
Il file [inline]stdbool.h[/inline] è parte dello standard C99, quindi dovresti poterlo usare senza problemi. All'atto pratico definisce delle macro per [inline]bool[/inline], [inline]true[/inline] e [inline]false[/inline], niente di più.

Comunque, mi sembra che sei arrivato abbastanza vicino alla soluzione e che ci stia provando. Ti mostro come l'avrei fatto io
#include <stdio.h> #include <stdbool.h> bool ric() { int n; scanf("%d", &n); if (n == 0) return true; else { if (n < 0) return !ric(); else return ric(); } } int main() { if (ric() == true) printf("Prodotto positivo"); else printf("Prodotto negativo"); return 0; }
Il file [inline]stdbool.h[/inline] è parte dello standard C99, quindi dovresti poterlo usare senza problemi. All'atto pratico definisce delle macro per [inline]bool[/inline], [inline]true[/inline] e [inline]false[/inline], niente di più.
Ok..
Ma cosa c'è che non va nell'ultima cosa che ho postato? E' per caso il fatto che uso una funzione con prototipo int...
e quindi restituirà un intero?
Ma cosa c'è che non va nell'ultima cosa che ho postato? E' per caso il fatto che uso una funzione con prototipo int...
e quindi restituirà un intero?
La parte nel caso n < 0 è un po' arzigogolata, a occhio sembra che funzioni però. L'hai provato? Funziona?