Newsgroup: it.comp.lang.c
Titolo: Facile su getchar()

Ho notato che ottengo un risultato strano su due costrutti che [perlomeno a
me] sembrano uguali dal punto di vista del risultato
Il primo e'
 c=getchar();
 while(c!='y' && c!='n')
   {
     putchar(c);
     c=getchar();
   }
Mentre il secondo e'
 while((c=getchar())!='y' && (c=getchar())!='n')
	putchar(c);
Se al secondo do come input aaaaaaaaaaaaaaaaaaaaaaaaa
questo  non mi ritorna tutte le 'a' che ho immesso ma solo alcune [il numero
cambia via via]
Il primo invece funziona bene.
Vi][oZ
 
-- 
Per rispondere togliere NONSCASSA da reply-to.

scusate, il server NNTP di Interbusiness dava errore e ho
insistito troppo con send.
ciao.

E' chiarissimo che per calcolare l' espressione di while
nel tuo secondo esempio,
finche' c non vale ne' 'y' ne' 'n' getchar() va chiamata
2 volte e che la seconda che il compilatore decide di
chiamare sovrascrive il valore della var c a prescindere
da quale sia l' ordine di valutazione degli operandi di &&.
Quandouno dei due potrebbe essere vero, l' ordine di valuta-
zione diviene motivo di diverso comportamento:
inserendo: aaaaaaaaaaaayaaaaaa
                       ^
se il compilatore valuta prima l' operando di sinistra
il ciclo si arresta (e se applica lo short evaluation non ha
bisogno neppure di chiamare la seconda getchar()), ma se per
caso valuta prima l' operando di destra, una unica 'y' non
basta perche' la prima viene confrontata con 'n' e all' espressione
restituisce 0, viene chiamata ancore getchar() che pero' assegna
a c la successiva 'a'.
prova il codice del secondo esempio con questi due input:
aaaaaaaayaaaaaa
aaaaaaaanaaaaaa
e poi cosi:
aaaayyaaaaaaa
aaaannaaaaaaa
Definirei il secondo esempio molto sbagliato.
ciao.



         putchar(c);
In questo caso č meglio che usi:
while ((c = getchar()) != 'y' && c != 'n')
            putchar(c);
altrimenti devi avere due 'yy' o due 'nn' di seguito perchč il programma faccia
ciň che vuoi.
Raffaele.

ciao.
Hai perfettamente ragione ma allora il metodo 
while((c=getchar())!='y' && c!='n')
...
E giusto no?!
Ve lo avevo detto che era facile...
e comunque grazie.


Raffaele.
Non vorrei sbagliare, ma non potendo assumere nulla sull'ordine di
valutazione di un'espressione, la parte
(c = getchar()) != 'y' && c != 'n'
dovrebbe essere (semanticamente?) errata.
Chiedo il parere degli esperti.
_____________________________________________________
Francesco Trotta
http://space.tin.it/computer/ftrotta
elimina "x_" dal mio indirizzo per le risposte

Il primo invece funziona bene.
Il primo è l'unico semanticamente corretto.
Infatti viene estratto un carattere per volta, come si dovrebbe.
Nel secondo, invece, ci può essere il caso peggiore che si verifica
quando vengono eseguite due chiamate a getchar().
Conseguentemente il risultato è diverso.
In un un'unica espressione del genere non dovrebbero esserci due
chiamate a getchar().
--
Andrea Laforgia        (
andrea_...@bigfoot.com
)

ciò che vuoi.
Temo che questa espressione abbia un comportamento indefinito, secondo
lo standard, infatti non c'è modo di stabilire se sia prima valutato
il valore di ritorno della funzione o prima il valore di c.
Si dovrebbero sempre evitare espressioni in cui si modifica una
variabile ed al tempo stesso si eseguono dei controlli su di essa, a
meno che non è esplicitamente riscontrabile la precedenza temporale
dei due eventi.
Per es. è lecito scrivere :
while ( ( c = getchar() ) != 'y' )  ...
ma non 
while ( i == vettore[i++] ) ...
--
Andrea Laforgia        (
andrea_...@bigfoot.com
)

>while ((c = getchar()) != 'y' && c != 'n')
[ snip ]
AL>Temo che questa espressione abbia un comportamento indefinito, secondo
AL>lo standard, infatti non c'è modo di stabilire se sia prima valutato
AL>il valore di ritorno della funzione o prima il valore di c.
Emerita sciocchezza:
[root@fokhouse /root]# grep -A 6 '^3.5' /usr/doc/FAQ/txt/C.FAQ
3.5:    But what about the && and || operators?
        I see code like "while((c = getchar()) != EOF && c != '\n')" ...
A:      There is a special exception for those operators (as well as the
        ?: and comma operators): left-to-right evaluation is guaranteed
        (as is an intermediate sequence point, see question 3.8).  Any
        book on C should make this clear.
[root@fokhouse /root]#
Ciao ciao,
Andrea
-- 
"...Unix, MS-DOS, and Windows NT (also known as the Good, the Bad, and 
 the Ugly)."
(by Matt Welsh)

 Per rispondere togliere NONSCASSA da reply-to.
Direi ancora di no, almeno volendo tenere uno standard come
riverimento. L' unico operatore per qui e' definito un ordine
di valutazione (da sinistra a destra) e la virgoola (,).
L' operatore logico && puo' liberamente calcolare le due espressioni
come vuole, anche in modo diverso in due istanze diverse e se
ti capita che prima calcoli l' espressione di destra, il valore
di c confrontato e' quello precedente alla getchar().
Con gli effetti collaterali bisogna stare attenti. Ci sono
regole da rispettare per poterli usare per ottimizzare il codice
senza compromettere la semantica del programma.
Comunque io credo che la prima versione che hai proposto non
abbia bisogno di ulteriori ottimizzazioni.
Ciao.

         book on C should make this clear.
                                     ^^^^^
My book in NOT clear.
thank you.
Non sapevo, Grazie.
ciao.

 dei due eventi.
Io pensavo che nel caso:
while ((c = getchar()) != 'y' && c != 'n')
la precedenza temporale fosse garantita dall'operatore '&&'. Tuttavia, se non è
così, meglio utilizzare la prima versione descritta di "Vi][oZ" che si sta più
sicuri ;-)
Raffaele.

 (c = getchar()) != 'y' && c != 'n'
Quello che dici è vero in generale, ma ci sono delle eccezzioni.
Gli operatori: &&, ||,?:, ',' sono sempre valutati con al regola "left_to_right".
Raffaele.

Grazie di avermi ricordato d'aver detto una fesseria, in effetti la
cosa mi sembrava abbastanza strana visto che il C dovrebbe assicurare
lo short-circuting, per il quale, appunto, si prevede un'eccezione.
--
Andrea Laforgia        (
andrea_...@bigfoot.com
)

la precedenza temporale fosse garantita dall'operatore '&&'.
Infatti č cosě, ricordavo che sul K&R, da qualche parte c'era scritto 
while ( ( c = getchar() ) != EOF && c != '\n' ) ...
&&, cosě come || ?: e la virgola, č uno di quegli operatori che
introduce nella valutazione dell'espressione un ulteriore "sequence
point", cioč uno di quei "momenti di riposo" della valutazione, in cui
ogni "side effect" č stato risolto e nessuna variabile sta ancora
attendendo di essere modificata.
E' necessario, quindi, prima di raggiungere questo "punto" della
sequenza di operazioni, che la chiamata a getchar() sia stata risolta
e che "c" sia stata modificata.
Da questo momento in poi si riprende la valutazione.
--
Andrea Laforgia        (
andrea_...@bigfoot.com
)

di c confrontato e' quello precedente alla getchar().
E' ormai chiaro che non č cosě, e credo che la scelta di lasciare
un'eccezione per l'operatore && sia motivata dal fatto che si assicura
che nei programmi si possa eseguire lo "short-circuiting".
Perchč in un programma si deve poter scrivere, per esempio :
if ( p != NULL && *p == 3 ) ...
In questo caso č necessario che p != NULL sia valutata prima di *p ==
3, in quanto, contrariamente, si potrebbe avere un errore di sistema.
Se si scrivesse, per esempio :
a = fn1() + fn2() ;
L'ordine di valutazione potrebbe essere indefinito, ma non nel caso di
a = fn1() && fn2() ; 
In cui fn1() č sicuramente eseguita prima di fn2().
--
Andrea Laforgia        (
andrea_...@bigfoot.com
)

Grazie. Molto utile questa info. Io finora ho fatto
acrobazie per evitare di non accedere al valore puntato
da un puntatore uguale a NULL. Avessi saputo prima...
ciao.

 wrote:
Giusto per puntualizzare, visto che ormai mi sembra sia chiaro a tutti  (me
compreso finalmente), cosa succede.
Seguendo tutto questo thread, mi stava venendo il dubbio che i signori
Kernighan e Ritchie avessero sbagliato impostando un 
while (--lim>0 && (c=getchar()) != EOF && c!='\n'
Ciao a tutti e grazie per le (copiose) risposte
