Newsgroup: it.comp.lang.c
Titolo: [niubbo] problemi con la lettura di dati immessi da console

Salve a tutti,
ho questo banalissimo codice:
int age;
char c;
printf("how old are you?\n");
scanf("%d", &age);
printf(" -- you said %d --\n",age);
printf("are you really %d? \n", age);
scanf("%c", &c);
//scanf(" %c", &c);
printf(" -- you said %c -- \n",c); //per debug;
if (c=='y')
     puts("ok!");
else puts("ah ah ah!");
ho notato che quando immetto l'età (scanf("%d", &age); ) digitando 
"88+invio" sulla mia tastiera, la stampa a video di debug subito sotto 
diventa
" -- you said 88
   --
"
ossia il valore di age è 88+invio, automaticamente a c viene assegnato 
il valore invio. Sono riuscito ad ovviare al problema mettendo uno 
spazio davanti a %c (riga commentata nel codice qui sopra), ma non c'è 
un modo per escludere l'"invio" nei dati immessi da tastiera?
Grazie,
Giulio

 un modo per escludere l'"invio" nei dati immessi da tastiera?
Premesso che:
http://c-faq.com/stdio/scanfprobs.html
La soluzione è non usare scanf. Leggi una riga di testo fino al primo "a 
capo" e poi la analizzi per estrarre i dati che ti servono.
-- 
Costantino Grana 

 capo" e poi la analizzi per estrarre i dati che ti servono.
L'esempio l'ho trovato così come era (in "Thinking in C" di Eckel e 
Aliston). Grazie anche del link che - ad essere sincero - non consocevo.
Ciao,
Giulio

, continuando comunque a trarre 
vantaggio dalle capacita' di parsing della funzione scanf.
Ciao
-- 
Cybertoldo
Per rispondermi via email, sostituisci moc.liamg con 
gmail.com

 un modo per escludere l'"invio" nei dati immessi da tastiera?
(leggi gli altri post di risposta)


 s).
Ottima idea. Concordo su tutta la linea. Un'altra proposta che mi permetto 
di fare č di allocare dinamicamente i buffer a seconda delle esigenze. 
Questa versione l'ho scritta adesso e non mi fiderei molto ad usarla alla 
cieca, perň mi sembra che renda l'idea. il buffer statico all'interno puň e 
anzi deve essere fatto piů grande, ma cosě si vede meglio il funzionamento.
char *getstring(void)
{
    char *pch;
    size_t size = 0;
    char buf[5];
    do {
        fgets (buf,sizeof(buf),stdin);
        if (size==0) {
            size = strlen(buf)+1;
            pch = malloc (size*sizeof(char));
            strcpy (pch,buf);
        }
        else {
            size += strlen(buf);
            pch = realloc (pch,size*sizeof(char));
            strcat (pch,buf);
        }
    } while (pch[strlen(pch)-1]!='\n');
    pch[strlen(pch)-1] = '\0';
    return pch;
}
-- 
Costantino Grana 


Senza spirito polemico, vorrei esporre un punto di vista diverso.
Questa  (di non usare scanf) è la soluzione che va per la maggiore nelle 
FAQ, e quindi nei NG.  Io trovo l'  atteggiamento delle FAQ  un po' 
troppo integralista.
Prima di scatenare i soliti flames tengo a precisare che conosco 
benissimo i problemi della scanf.
Tuttavia preferisco prendere un atteggiamento più  possibilista.
Tutto sommato  lo specifico problema in questione è pur stato risolto 
dall'  OP,  nonostante la sua (auto)catalogazione  come niubbo :-).
Personalmente penso che la scanf *possa* essere utilizzata se valgono 
due condizioni:
1. si conosce il suo comportamento;
2. si desidera una soluzione semplice e  veloce (anche se non robusta) 
alla lettura di dati da stdin (il caso 
p.es
. di molte letture fatte da 
prototipi o  programmi in via di sviluppo/debugging).
Va  da sé  che se invece uno deve scrivere  una function di lettura "a 
prova di bomba" e con  possibilità  di verifica e/o  correzione dell' 
input altre soluzioni sono d'  obbligo.
Ma non vedo perché  dover rinunciare definitivamente ad una function di 
input  che, in alcuni casi (
p.es
. per chi si avvicina al linguaggio per 
la prima volta) e  con qualche precauzione,  permette di avere quello 
che c' e'  in  quasi tutti i linguaggi di alto livello:  un metodo 
semplice per immettere dati sotto forma di caratteri e trasformarli 
nella rappresentazione interna.
Giorgio

 anzi deve essere fatto più grande, ma così si vede meglio il funzionamento.
Infatti :)
una volta risolto (in qualche modo) i problemi della scanf, poi dobbiamo 
risolvere quelli della fgets. Ovvero... piu' che di problemi qui si 
parla di limiti: la fgets puo' non riuscire a leggere una linea completa 
(dim. insufficiente del buffer passato alla funz.) restituendola tronca. 
Questa dara' poi anche un input errato alla successiva procedura di parsing.
La tua idea, "di base", sarebbe corretta: ovvero di operare per realloc 
successive fino al completamento della linea. A parte i controlli di 
errore mancanti (che avrai omesso volutamente per far vedere meglio i 
passaggi) c'e' un problema nell'algoritmo di individuazione della linea 
di testo: quest'ultima non sempre termina con uno '\n' anche quando e' 
intera. Mi riferisco al caso specifico dell' *ultima* linea di un file 
di testo (ma puo' succedere anche con un input proveniente da tastiera) 
prima di incontrare la condizione di EOF. La funzione getstring() 
andrebbe quindi modificata per comprendere anche questo caso specifico.
===
Se ti puo' essere utile come riferimento, tempo fa avevo postato sul ng 
una funzione [1] tipo la tua (anche se usava la fgetc anziche' la fgets):
http://groups.google.it/group/it.comp.lang.c/msg/cd22f37187f3e472
Gli avevo inoltre dato la possibilita' di riutilizzare i puntatori 
restituiti da una precedente chiamata, evitando quindi delle continue 
free().
===
Volendola utilizzare per l'esempio di prima, il codice sarebbe diventato 
(sempre con i controlli d'errore ridotti al minimo):
~~~~~~~~~~~
int age;
char c;
char *pBf = NULL; /* importante == NULL ! */
printf("how old are you?\n");
age = 0; /* inizializzare sempre ad un valore */
if((pBf = dyn_fgets(stdin, pBf, NULL)))
	sscanf(pBf, "%d", &age);
printf(" -- you said %d --\n",age);
printf("are you really %d? \n", age);
c = ' '; /* inizializzare sempre ad un valore */
if((pBf = dyn_fgets(stdin, pBf, NULL)))
	sscanf(pBf, " %c", &c);
printf(" -- you said %c -- \n",c); //per debug;
if (c=='y')
	puts("ok!");
else	puts("ah ah ah!");
if(pBf)
          free(pBf);
~~~~~~~~~~~
[1] ti prego di non scandalizzarti per alcuni 'goto' su condizione 
d'errore... - in caso contrario, prova a toglierli. Ma senza peggiorare 
la leggibilita' del codice od omettere alcuni controlli :)


 nella rappresentazione interna.
Se si vuole tenere lontano gli studenti dai problemi del C (perche' 
troppo vicino alla macchina e quindi si desidera avere un ambiente con 
un livello di astrazione superiore), perche' allora non sostituirlo 
nell'insegnamento con un linguaggio di piu' alto livello?
Per insegnare le basi della programmazione un tempo ricorrevano al buon 
vecchio Pascal, "concepito" proprio (anzi: solamente) per essere uno 
strumento didattico. Forse oggi si puo' scegliere un altro linguaggio 
con caratteristiche didattiche simili, magari anche meno noioso, e piu' 
utile nella pratica...
Ma se la scuola sceglie il C, probabilmente e' perche' si "vuole" 
(anche) insegnare allo studente come interagire con determinate logiche 
piu' vicine alla macchina; quindi di renderlo pure consapevole di cosa 
"veramente" accada aprendo uno stream; quindi di metterlo in condizioni 
di potersela cavare anche davanti ad un /grezzo/ flusso di dati.
La maggior parte degli studenti che ora studiano il C, un domani 
programmeranno (se lo dovranno fare di professione) in un altro 
linguaggio - probabilmente quello ritenuto piu' produttivo per l'azienda 
dove verranno assunti. L'aver, pero', "ben capito" le logiche di 
funzionamento della macchina (quelle che oggi si preferirebbe tentare di 
nascondergli per non perdere eccessivo tempo) rappresenteranno per lui 
un grande vantaggio rispetto a chi ha imparato a programmare in un 
linguaggio di piu' alto livello.
Ciao (scusa il testo scritto di fretta)


 linguaggio di piu' alto livello.
Concordo. Anche se  secondo me un buon programmatore dovrebbe fare 
esperienza di un certo numero di linguaggi (possibilmente appartenenti a 
diverse famiglie e paradigmi di programmazione)  per avere veramente 
quell'  apertura mentale che sola permette di adegguarsi in fretta ad un 
altro (nuovo)  linguaggio di programmazione.
Giorgio