Esercizio con gli operatori ?

vincenzoj
#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
Super Squirrel
Quando si utilizza &&, il secondo operando (quello a destra di &&) viene valutato solo se il primo operando restituisce vero.

apatriarca
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.

vincenzoj
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.

apatriarca
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.

vincenzoj
Ok quindi ora dovrei fare prima 1%2 e poi decrementarlo.
1%2 = 0 che decrementato diventa -1. -1==0 che è falso. Giusto ?

apatriarca
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.

vincenzoj
Perchè alla fine viene stampato 4 come risultato ?

apatriarca
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.

vincenzoj
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 ?

apatriarca
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..

vincenzoj
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.

apatriarca
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ò..

Albesa81
"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...

apatriarca
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.

vincenzoj
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].

apatriarca
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.

vincenzoj
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);
}
}

apatriarca
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;
}

vincenzoj
Ok perfetto. Grazie di tutto.

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.