Esercizio con gli operatori ?
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main() { int a = 5, b = 3, c = 0; if (!b--&&++a || !c-- % 2 == 0) c -= 3 * a; else if (!(a % 2 == 0) || ((b++) && (a--))) a--; b++; switch (++b - c) { case 0: printf("%d - ", a); case 1: printf("%d - ", b); break; case 2: printf("%d - ", c); default: printf("%d", a); } }
Devo trovare il valore stampato da questo programma. Ora io sto provando a risolverlo passo passo con il debug su Visual Studio. Analizzando i valori al primo if mi viene a = 5, b= 2, c=-1. Con b mi trovo, ma perchè a= 5 e c=-1 ? Non dovrebbe essere a = 6(visto che viene incrementato) e c=-16 ?
Risposte
Quando si utilizza &&, il secondo operando (quello a destra di &&) viene valutato solo se il primo operando restituisce vero.
Gli operatori && e || eseguono l'espressione alla loro destra solo se necessario. Nel caso di && l'espressione destra viene eseguita solo se quella a sinistra è vera, nel caso di || se l'espressione è falsa. Siccome !b-- è falsa (3 è non nullo e quindi vero e il ! la fa diventare falsa) l'istruzione alla destra non viene valutata. A questo punto viene eseguita l'istruzione a destra dell'|| che è falsa e quindi il corpo dell'if non viene valutato. Alla fine b viene quindi decrementato, a rimane uguale a se stesso (perché la relativa istruzione non viene eseguita) e c viene decrementato di 1.
Ma l'istruzione a destra dell'|| perchè è falsa ? Io ho !c--%2 == 0, quindi c=0, che viene decrementato e diventa -1, poi diventa non -1, quindi 0 e 0%2 è 0. Quindi alla fine si ottiene 0==0 che è 1 e quindi vera.
Il valore viene modificato dopo essere stato usato. Se fosse stato scritto !--c avresti avuto ragione, ma così c vale ancora 0 e quindi quando viene negato diventa 1. Dopo aver valutato la tua istruzione c viene decrementato.
Ok quindi ora dovrei fare prima 1%2 e poi decrementarlo.
1%2 = 0 che decrementato diventa -1. -1==0 che è falso. Giusto ?
1%2 = 0 che decrementato diventa -1. -1==0 che è falso. Giusto ?
No, l'unico valore di c che interviene nella condizione dell'if è quello iniziale. Quindi 0. Il fatto che sia decrementato dopo non ha alcun effetto sulla condizione.
Perchè alla fine viene stampato 4 come risultato ?
Perché subito prima dello switch abbiamo a=4, b=3 e c=-1. Il numero che viene considerato nello switch ha valore 5 essendo b incrementato prima di ottenere il valore dell'espressione. 5 va a finire in default e quindi viene stampato il valore di a che è 4.
Ma quindi anche se il primo corpo dell'if risulta falso, i valori delle variabili dell'else if non sono più quelli iniziali, ma quelli che che derivano dal primo if ?
Non mi è chiara la domanda. I valori sono quelli che dipendono da quello che è avvenuto valutando la condizione. Per cui sono certamente i valori che devi usare nell'else if..
Mi spiego meglio : se io ho come valori iniziali a = 5, b=3 e c=0, valuto il primo if, se quest'ultimo mi risulta falso, valuto l'else if. Ora la mia domanda è la seguente : se l'if è falso e in quest'ultimo ci sono degli incrementi/decrementi, nell'else if parto sempre dai valori iniziali, ossia a = 5, b=3 e c=0, oppure da quelli modificati dal primo if ?
Inoltre ti chiedo anche se puoi suggerirmi alcuni siti ( con teoria ed esercizi ) dove posso chiarire questo argomento. Io ora sto usando il Bellini-Guidi come libro, ma questo argomento non mi è del tutto chiaro.
Inoltre ti chiedo anche se puoi suggerirmi alcuni siti ( con teoria ed esercizi ) dove posso chiarire questo argomento. Io ora sto usando il Bellini-Guidi come libro, ma questo argomento non mi è del tutto chiaro.
Una volta che una variabile viene modificata non c'è alcun modo per tornare indietro. Se quindi modifichi qualcosa nella condizione di un if o di un ciclo o altro, questa modifica sarà visibile in qualsiasi codice eseguito in seguito. Per cui il tuo "else if" vedrà i valori modificati all'interno della condizione del primo if.
L'esercizio è comunque abbastanza estremo e anche una persona con anni di esperienza ha bisogno di stare molto attento a capire cosa sta succedendo in un codice del genere. Si tratta di un esempio di codice che si spera di non vedere mai in pratica e che, se mi capitasse di trovarlo, modificherei subito per essere più chiaro. Non ti preoccupare quindi se lo trovi complicato. Detto questo, qualsiasi libro di testo del C++ che spieghi nel dettagli il funzionamento di qualsiasi istruzione è adatto al tuo scopo. Non ti saprei indicare siti o libri con esercizi di questo tipo però..
L'esercizio è comunque abbastanza estremo e anche una persona con anni di esperienza ha bisogno di stare molto attento a capire cosa sta succedendo in un codice del genere. Si tratta di un esempio di codice che si spera di non vedere mai in pratica e che, se mi capitasse di trovarlo, modificherei subito per essere più chiaro. Non ti preoccupare quindi se lo trovi complicato. Detto questo, qualsiasi libro di testo del C++ che spieghi nel dettagli il funzionamento di qualsiasi istruzione è adatto al tuo scopo. Non ti saprei indicare siti o libri con esercizi di questo tipo però..
"simonerusso64":
se l'if è falso e in quest'ultimo ci sono degli incrementi/decrementi, nell'else if parto sempre dai valori iniziali, ossia a = 5, b=3 e c=0, oppure da quelli modificati dal primo if ?
Il costrutto "if" ha una condizione e un corpo.
Se ti riferisci alla condizione, ha già detto tutto apatriarca.
Se ti riferisci al corpo, se l'"if è falso" questo non verrà eseguito, quindi...
Quindi non ha alcuna importanza. La modifica dei valori avviene durante la valutazione della condizione e non nel corpo dell'if che giustamente non viene valutato.
Ma nel mio caso :
if (!b--&&++a || !c-- % 2 == 0) c -= 3 * a
qual è il corpo e quale la condizione ?
Io so che la BNF dell'if è :
if(espressione) istruzione1 [else istruzione2].
if (!b--&&++a || !c-- % 2 == 0) c -= 3 * a
qual è il corpo e quale la condizione ?
Io so che la BNF dell'if è :
if(espressione) istruzione1 [else istruzione2].
L'espressione tra le parentesi tonde, quella che chiamo la condizione dell'if, viene sempre valutata al fine di sapere cosa eseguire. Se la valutazione di questa espressione richiede la modifica di alcune variabili allora queste modifiche vengono ovviamente mantenute nel resto del codice indipendentemente dall'effettivo valore dell'espressione. Quando una variabile viene cambiata, è per sempre, non esiste un modo per tornare indietro e ottenere il suo valore precedente.
Ok.
Siccome ci sono ancora punti che non mi sono chiari e non vorrei farvi perdere ulteriore tempo, vi chiedo se mi potete risolvere l'esercizio commentando i vari passi.
Vi ripropongo la traccia dell'esercizio :
Cosa stampa il seguente frammento di programma con i valori delle variabili specificati ?
#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
int a = 5, b = 3, c = 0;
if (!b--&&++a || !c-- % 2 == 0) c -= 3 * a;
else if (!(a % 2 == 0) || ((b++) && (a--))) a--; b++;
switch (++b - c) {
case 0: printf("%d - ", a);
case 1: printf("%d - ", b); break;
case 2: printf("%d - ", c);
default: printf("%d", a);
}
}
Siccome ci sono ancora punti che non mi sono chiari e non vorrei farvi perdere ulteriore tempo, vi chiedo se mi potete risolvere l'esercizio commentando i vari passi.
Vi ripropongo la traccia dell'esercizio :
Cosa stampa il seguente frammento di programma con i valori delle variabili specificati ?
#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
int a = 5, b = 3, c = 0;
if (!b--&&++a || !c-- % 2 == 0) c -= 3 * a;
else if (!(a % 2 == 0) || ((b++) && (a--))) a--; b++;
switch (++b - c) {
case 0: printf("%d - ", a);
case 1: printf("%d - ", b); break;
case 2: printf("%d - ", c);
default: printf("%d", a);
}
}
Il codice dovrebbe essere equivalente a questo codice molto più lungo ma più semplice.
#include <stdio.h> int main(int argc, char const *argv[]) { int a = 5; int b = 3; int c = 0; // e_1 rappresenta !b-- int e_1 = !b; // e_1 = 0 b = b - 1; // b = 2 // e_2 rappresenta !b-- && ++a int e_2 = e_1; // e_2 = 0 if (e_1) { // Non eseguito a = a + 1; e_2 = a; } // e_3 rappresenta !b--&&++a || !c-- % 2 == 0 int e_3 = e_2; // e_3 = 0 if (!e_2) { // Viene eseguito int e_4 = !c; // e_4 = 1 c = c - 1; // c = -1 e_3 = e_4 % 2 == 0; // 0 } if (e_3) { // Non eseguito c = c - 3*a; } if (!e_3) { // Eseguito int e_5 = !(a%2 == 0); // e_5 = 1 if (!e_5) { // Non eseguito e_5 = b; b = b + 1; if (e_5) { e_5 = a; a = a - 1; } } if (e_5) { // Eseguito a = a - 1; // a = 4 b = b + 1; // b = 3 } } b = b + 1; // b = 4; int e_6 = b - c; // e_6 = 5; if (e_6 == 0) { // Non eseguito printf("%d - ", a); } if (e_6 == 0 || e_6 == 1) { // Non eseguito printf("%d - ", b); } if (e_6 == 2) { // Non eseguito printf("%d - ", c); } if (e_6 != 0 && e_6 != 1) { // Eseguito printf("%d", a); // Stampa 4 } return 0; }
Ok perfetto. Grazie di tutto.