Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Microsoft Surface Pro 12 è il 2 in 1 più compatto e silenzioso
Microsoft Surface Pro 12 è il 2 in 1 più compatto e silenzioso
Basato su piattaforma Qualcomm Snapdragon X Plus a 8 core, il nuovo Microsoft Surface Pro 12 è un notebook 2 in 1 molto compatto che punta sulla facilità di trasporto, sulla flessibilità d'uso nelle differenti configurazioni, sul funzionamento senza ventola e sull'ampia autonomia lontano dalla presa di corrente
Recensione REDMAGIC Astra Gaming Tablet: che spettacolo di tablet!
Recensione REDMAGIC Astra Gaming Tablet: che spettacolo di tablet!
Il REDMAGIC Astra Gaming Tablet rappresenta una rivoluzione nel gaming portatile, combinando un display OLED da 9,06 pollici a 165Hz con il potente Snapdragon 8 Elite e un innovativo sistema di raffreddamento Liquid Metal 2.0 in un form factor compatto da 370 grammi. Si posiziona come il tablet gaming più completo della categoria, offrendo un'esperienza di gioco senza compromessi in mobilità.
Dopo un mese, e 50 foto, cosa abbiamo capito della nuova Nintendo Switch 2
Dopo un mese, e 50 foto, cosa abbiamo capito della nuova Nintendo Switch 2
Dopo un mese di utilizzo intensivo e l'analisi di oltre 50 scatti, l'articolo offre una panoramica approfondita di Nintendo Switch 2. Vengono esaminate le caratteristiche che la definiscono, con un focus sulle nuove funzionalità e un riepilogo dettagliato delle specifiche tecniche che ne determinano le prestazioni
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 03-06-2007, 10:23   #1
uomoserio
Senior Member
 
L'Avatar di uomoserio
 
Iscritto dal: Aug 2000
Messaggi: 608
Controllo input in C/C++: alcune domande.

Ciao a tutti, avrei bisogno di qualche delucidazione sulla gestione dell'input da tastiera in C/C++.
Di seguito è il classico giochino "indovina il numero", sulla base del quale avrei alcune domande da farvi per gestire le immissioni da tastiera da parte dell'utente:

Codice:
#include <cstdlib>
#include <iostream>
#include <ctime>
using namespace std;

unsigned int insNumero();
void gioco();

int main()
{
    char again;
    do {            
        gioco();
        do{    
               printf("\n\nVuoi giocare ancora? [s/n] ");
               again=getchar();
               fflush(stdin);
               if (again!='s' && again!='n') printf("\nScelta non consentita. Premi 's' o 'n'");
        } while (again!='s' && again!='n');
    } while (again=='s');
    
    return 0;
}

unsigned int insNumero()
{
         int numInserito;
         do{
             printf("\nInserisci il numero: ");
             scanf("%u", &numInserito);
             if (numInserito==0 || numInserito > 100) printf("\nDevi inserire un numero da 1 a 100!!!\n");
             fflush(stdin);
         } while(numInserito==0 || numInserito > 100);
         return numInserito;
}

void gioco()
{
     unsigned int numMagico;
     unsigned int numIndovina;
     srand(time(NULL));
     numMagico=(rand()%100)+1;
     printf("\n\nIndovina il numero magico da 1 a 100\n");
     do {
         numIndovina=insNumero();
         if (numIndovina < numMagico) printf("\nHai inserito un numero troppo basso.\n");
         else if (numIndovina > numMagico) printf("\nHai inserito un numero troppo alto.\n");
              else {
                   printf("COMPLIMENTI!!!\n");
                   printf("Il numero magico era proprio: %u", numMagico);
              }
     } while (numIndovina != numMagico);
     return;
}
Domanda 1: nella funzione insNumero(), ho usato un metodo spicciolo per controllare che il valore immesso sia compreso fra 1 e 100, così se l'utente immette dei caratteri invece di numeri il controllo comunque lo blocca (altrimenti il programma si impalla di brutto!). Ma se io avessi voluto verificare a priori il tipo immesso dall'utente (caratteri o numeri) come dovevo fare?

Domanda 2: per evitare i soliti problemi con i caratteri rimanenti nel buffer di immissione, dopo ogni inserimento da parte dell'utente ho usato fflush(stdin) per svuotare il buffer ed evitare che all'immisione successiva venissero presi eventuali caratteri residui. Questo è un sistema corretto? Oppure esiste un sistema migliore per controllare l'eccedenza del buffer di stdin? Inoltre la funzione fflush(stdin) l'ho trovata cercando nei forum....ma possibile che nessun manuale di C/C++, fra le decine che possiedo, si degni di spiegare queste cose? Eppure il problema della ingestibilità del buffer di input è un problema molto diffuso, a quanto leggo in giro....

Domanda 3: per ora il programma è scritto in C, usando le funzioni standard printf e scanf. Ma se io avessi voluto rimanere sul C++ e usare cin per le immissioni dell'utente, in che modo si utilizza esattamente? So che la forma generale con l'operatore estrattore è "cin >> variabile", ma in che modo posso formattare l'input (come ad esempio"%u" in scanf) per essere sicuro che mi restituisca un valore e non un carattere?

Grazie per la pazienza.
__________________
Intel Core2Quad Q6600 2,4GHz @ 3,0 GHz
2 Gb RAM 667 MHz
ATI HD2900XT
uomoserio è offline   Rispondi citando il messaggio o parte di esso
Old 03-06-2007, 11:05   #2
andbin
Senior Member
 
L'Avatar di andbin
 
Iscritto dal: Nov 2005
Città: TO
Messaggi: 5206
Quote:
Originariamente inviato da uomoserio Guarda i messaggi
Domanda 1: nella funzione insNumero(), ho usato un metodo spicciolo per controllare che il valore immesso sia compreso fra 1 e 100, così se l'utente immette dei caratteri invece di numeri il controllo comunque lo blocca (altrimenti il programma si impalla di brutto!). Ma se io avessi voluto verificare a priori il tipo immesso dall'utente (caratteri o numeri) come dovevo fare?
Avresti dovuto usare funzioni a più basso livello e non standard, es. getch() o le API Win32 se stai lavorando su Windows.

Quote:
Originariamente inviato da uomoserio Guarda i messaggi
Domanda 2: per evitare i soliti problemi con i caratteri rimanenti nel buffer di immissione, dopo ogni inserimento da parte dell'utente ho usato fflush(stdin) per svuotare il buffer ed evitare che all'immisione successiva venissero presi eventuali caratteri residui. Questo è un sistema corretto? Oppure esiste un sistema migliore per controllare l'eccedenza del buffer di stdin? Inoltre la funzione fflush(stdin) l'ho trovata cercando nei forum....ma possibile che nessun manuale di C/C++, fra le decine che possiedo, si degni di spiegare queste cose? Eppure il problema della ingestibilità del buffer di input è un problema molto diffuso, a quanto leggo in giro....
fflush(stdin) non va molto bene. Secondo le specifiche, fflush va usato solo con stream di output, perché con stream di input il comportamento è indefinito (sebbene in alcuni ambienti fa proprio quello che vuoi, cioè pulire il buffer di input).
Ci sono altri modi per eliminare i caratteri in più:
- Fare un ciclo while(getchar() != '\n');
- Evitare scanf e usare fgets/sscanf

Quote:
Originariamente inviato da uomoserio Guarda i messaggi
Domanda 3: per ora il programma è scritto in C, usando le funzioni standard printf e scanf. Ma se io avessi voluto rimanere sul C++ e usare cin per le immissioni dell'utente, in che modo si utilizza esattamente? So che la forma generale con l'operatore estrattore è "cin >> variabile", ma in che modo posso formattare l'input (come ad esempio"%u" in scanf) per essere sicuro che mi restituisca un valore e non un carattere?
In effetti hai fatto un po' un mix ... hai usato roba del "C" (scanf, printf) ma poi hai incluso roba del C++. Evita questi mix.
__________________
Andrea, SCJP 5 (91%) - SCWCD 5 (94%)
andbin è offline   Rispondi citando il messaggio o parte di esso
Old 03-06-2007, 11:15   #3
ndakota
Senior Member
 
L'Avatar di ndakota
 
Iscritto dal: Oct 2006
Città: milano
Messaggi: 1439
in effetti iostream e namespace std li potrebbe anche togliere no?
ndakota è offline   Rispondi citando il messaggio o parte di esso
Old 03-06-2007, 13:41   #4
uomoserio
Senior Member
 
L'Avatar di uomoserio
 
Iscritto dal: Aug 2000
Messaggi: 608
Quote:
Originariamente inviato da andbin Guarda i messaggi
Avresti dovuto usare funzioni a più basso livello e non standard, es. getch() o le API Win32 se stai lavorando su Windows.
Per ora faccio cose in console, sto appena imparando, niente API Win32.
Ma getch() e sua sorella getche() servono per leggere caratteri da stdin senza buffer, giusto? Come posso usarlo per verificare se l'utente digita dei caratteri invece che dei numeri? E poi mi sembra che getch() restituisca un tipo char, come lo uso per inserire valori in variabili int?

Quote:
Originariamente inviato da andbin Guarda i messaggi
fflush(stdin) non va molto bene. Secondo le specifiche, fflush va usato solo con stream di output, perché con stream di input il comportamento è indefinito (sebbene in alcuni ambienti fa proprio quello che vuoi, cioè pulire il buffer di input).
Ci sono altri modi per eliminare i caratteri in più:
- Fare un ciclo while(getchar() != '\n');
- Evitare scanf e usare fgets/sscanf
Hai ragione, in effetti non avevo pensato al ciclo while per svuotare il buffer. Semplice e veloce, grazie
Da quello che ho letto fgets e sscanf servono per le stringhe....dovrei usare quelli per ricevere numeri dal stdin? Ma poi hanno comunque il problema del buffer, giusto? Quindi dovrei in ogni caso svuotarlo, vero?

Quote:
Originariamente inviato da andbin Guarda i messaggi
In effetti hai fatto un po' un mix ... hai usato roba del "C" (scanf, printf) ma poi hai incluso roba del C++. Evita questi mix.
Per il mix col C++ ti riferisci all'uso di <iostream> con "using namespace std"? In effetti originariamente avevo scritto il programma usando cin e cout, ma poi li ho sostituiti perchè non riuscivo a capire come gestirli.
__________________
Intel Core2Quad Q6600 2,4GHz @ 3,0 GHz
2 Gb RAM 667 MHz
ATI HD2900XT
uomoserio è offline   Rispondi citando il messaggio o parte di esso
Old 03-06-2007, 15:05   #5
marco.r
Senior Member
 
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
Quote:
Originariamente inviato da uomoserio Guarda i messaggi
Ciao a tutti, avrei bisogno di qualche
Domanda 1: nella funzione insNumero(), ho usato un metodo spicciolo per controllare che il valore immesso sia compreso fra 1 e 100, così se l'utente immette dei caratteri invece di numeri il controllo comunque lo blocca (altrimenti il programma si impalla di brutto!). Ma se io avessi voluto verificare a priori il tipo immesso dall'utente (caratteri o numeri) come dovevo fare?
Se vuoi usare gli stream del C++, puoi fare qualcosa di simile al seguente:
Codice:
#include <iostream>
using namespace std;

/* ... */
int n;
cin >> n
if ( cin.fail() ) // ho inserito dei caratteri
{
  cin.clear();
  while( !isdigit( cin.peek() ) ) cin.ignore();
}
Questo fa si' che in caso di errore vengano ignorati tutti i caratteri fino alla prima cifra.
Se preferisci che venga ignorata tutta la riga, allora puoi fare nel modo seguente
Codice:
#include <iostream>
using namespace std;

/* ... */
int n;
cin >> n
if ( cin.fail() ) // ho inserito dei caratteri
{
  cin.clear();
  while( cin.peek() != '\n' ) cin.ignore();
}
Vedi tu quale sia piu' adatto al tuo caso

Quote:
Domanda 2: per evitare i soliti problemi con i caratteri rimanenti nel buffer di immissione, dopo ogni inserimento da parte dell'utente ho usato fflush(stdin) per svuotare il buffer ed evitare che all'immisione successiva venissero presi eventuali caratteri residui. Questo è un sistema corretto? Oppure esiste un sistema migliore per controllare l'eccedenza del buffer di stdin? Inoltre la funzione fflush(stdin) l'ho trovata cercando nei forum....ma possibile che nessun manuale di C/C++, fra le decine che possiedo, si degni di spiegare queste cose? Eppure il problema della ingestibilità del buffer di input è un problema molto diffuso, a quanto leggo in giro....
No, flush va bene solo con l'output. Se anche funzionasse (ovvero svuotando il buffer di input) non puoi avere la certezza che questo contenga una sola linea di testo

Quote:
Domanda 3: per ora il programma è scritto in C, usando le funzioni standard printf e scanf. Ma se io avessi voluto rimanere sul C++ e usare cin per le immissioni dell'utente, in che modo si utilizza esattamente? So che la forma generale con l'operatore estrattore è "cin >> variabile", ma in che modo posso formattare l'input (come ad esempio"%u" in scanf) per essere sicuro che mi restituisca un valore e non un carattere?
Nel tuo caso, vedi la prima riga: basta usare una variabile del tipo opportuno, ven,tuali input non previsti settano lo stato del canale su "fail". In generale non puoi formattare l'input allo stesso modo in cui usi una scanf, ci si puo' arrivare vicino leggendo l'input in variabili del tipo opportuno, ed ignorando i caratteri che non ti interessano.
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele

Ultima modifica di marco.r : 03-06-2007 alle 15:06. Motivo: tag sbagliati...
marco.r è offline   Rispondi citando il messaggio o parte di esso
Old 03-06-2007, 15:26   #6
uomoserio
Senior Member
 
L'Avatar di uomoserio
 
Iscritto dal: Aug 2000
Messaggi: 608
Quote:
Originariamente inviato da marco.r Guarda i messaggi
Se vuoi usare gli stream del C++, puoi fare qualcosa di simile al seguente:
Codice:
#include <iostream>
using namespace std;

/* ... */
int n;
cin >> n
if ( cin.fail() ) // ho inserito dei caratteri
{
  cin.clear();
  while( !isdigit( cin.peek() ) ) cin.ignore();
}
Questo fa si' che in caso di errore vengano ignorati tutti i caratteri fino alla prima cifra.
Se preferisci che venga ignorata tutta la riga, allora puoi fare nel modo seguente
Codice:
#include <iostream>
using namespace std;

/* ... */
int n;
cin >> n
if ( cin.fail() ) // ho inserito dei caratteri
{
  cin.clear();
  while( cin.peek() != '\n' ) cin.ignore();
}
Vedi tu quale sia piu' adatto al tuo caso
Grazie!
E' esattamente quello che cercavo. Sapevo che cin adatta l'input alla variabile che lo deve contenere, ma non conoscevo tutte le sottofunzioni peek, fail, clear e ignore.
A dire il vero avevo visto queste cose qui:
http://www.cplusplus.com/reference/iostream/istream/
ma non ci ho capito un gran ché, forse perchè sono agli inizi!

Quote:
Originariamente inviato da marco.r Guarda i messaggi
No, flush va bene solo con l'output. Se anche funzionasse (ovvero svuotando il buffer di input) non puoi avere la certezza che questo contenga una sola linea di testo
In effetti me lo avete già detto in tanti, però a me funziona. Poi l'ho trovato scritto in molti forum, come soluzione di svuotamento del buffer.
Comunque ora che mi hai dato la soluzione migliore la sostituisco senza dubbio.

Grazie di tutto.
__________________
Intel Core2Quad Q6600 2,4GHz @ 3,0 GHz
2 Gb RAM 667 MHz
ATI HD2900XT
uomoserio è offline   Rispondi citando il messaggio o parte di esso
Old 04-06-2007, 14:18   #7
uomoserio
Senior Member
 
L'Avatar di uomoserio
 
Iscritto dal: Aug 2000
Messaggi: 608
Quote:
Originariamente inviato da marco.r Guarda i messaggi
No, flush va bene solo con l'output. Se anche funzionasse (ovvero svuotando il buffer di input) non puoi avere la certezza che questo contenga una sola linea di testo
Ok, come suggerito da andbin, per svuotare il buffer posso usare:
Codice:
while (getchar()!='\n')
che va benissimo, in effetti. Ma per usare esclusivamente le funzioni di I/O del C++, ho sostituito getchar() con cin.get() nel ciclo while, però in caso di errore non funziona. Perchè?
Prendi questo codice:
Codice:
#include <iostream>
using namespace std;

int main()
{
    int x;
    cout << "Inserisci un numero: ";
    cin >> x;
    if (cin.fail()) cout << "\nErrore";
       else cout << "\nHai digitato: " << x;
    while (cin.get()!='\n');
    cin.get();
    return 0;
}
Se io immetto un numero, procede tutto bene.
Ma se io, invece, inserisco uno o più caratteri, il programma stampa correttamente il messaggio "Errore" (sfruttando la funzione cin.fail() ), però poi si pianta nel ciclo while di svuotamento.
Da quello che ho capito dal comportamento, in caso di errore nello stream di input non esiste più '\n' e il ciclo while diventa infinito!

Quindi come risolvo? Cosa devo cercare invece di '\n'?
__________________
Intel Core2Quad Q6600 2,4GHz @ 3,0 GHz
2 Gb RAM 667 MHz
ATI HD2900XT
uomoserio è offline   Rispondi citando il messaggio o parte di esso
Old 04-06-2007, 17:27   #8
marco.r
Senior Member
 
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
Quote:
Originariamente inviato da uomoserio Guarda i messaggi
Codice:
#include <iostream>
using namespace std;

int main()
{
    int x;
    cout << "Inserisci un numero: ";
    cin >> x;
    if (cin.fail()) cout << "\nErrore";
       else cout << "\nHai digitato: " << x;
    while (cin.get()!='\n');
    cin.get();
    return 0;
}
Quindi come risolvo? Cosa devo cercare invece di '\n'?
A naso direi che ti sei dimenticato di impostare su "pulito" lo stato del canale con cin.clear() prima del ciclo while, per cui le chiamate successive a cin.get() falliscono tutte.
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele
marco.r è offline   Rispondi citando il messaggio o parte di esso
Old 04-06-2007, 17:43   #9
uomoserio
Senior Member
 
L'Avatar di uomoserio
 
Iscritto dal: Aug 2000
Messaggi: 608
Quote:
Originariamente inviato da marco.r Guarda i messaggi
A naso direi che ti sei dimenticato di impostare su "pulito" lo stato del canale con cin.clear() prima del ciclo while, per cui le chiamate successive a cin.get() falliscono tutte.
Cavolo, hai ragione!!
Infatti adesso funziona, e in questo modo sono riuscito anche a trasformare il giochino del numero in modo da usare soltanto istruzioni C++ e abbandonare quelle standard del C.
Grazie infinite!
__________________
Intel Core2Quad Q6600 2,4GHz @ 3,0 GHz
2 Gb RAM 667 MHz
ATI HD2900XT
uomoserio è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Microsoft Surface Pro 12 è il 2 in 1 più compatto e silenzioso Microsoft Surface Pro 12 è il 2 in 1 pi&u...
Recensione REDMAGIC Astra Gaming Tablet: che spettacolo di tablet! Recensione REDMAGIC Astra Gaming Tablet: che spe...
Dopo un mese, e 50 foto, cosa abbiamo capito della nuova Nintendo Switch 2 Dopo un mese, e 50 foto, cosa abbiamo capito del...
Gigabyte Aero X16 Copilot+ PC: tanta potenza non solo per l'IA Gigabyte Aero X16 Copilot+ PC: tanta potenza non...
vivo X200 FE: il top di gamma si è fatto tascabile? vivo X200 FE: il top di gamma si è fatto ...
Driver più sicuri: Microsoft alza...
Ego Power+ ha la giusta accoppiata per l...
Scompiglio nei listini Amazon: prezzi im...
Sotto i 105€ il robot Lefant che lava, a...
Mini proiettori smart in offerta: uno co...
Smartwatch Amazfit in offerta: Balance o...
Windows XP ritorna: ecco come usarlo sub...
Arrow Lake in saldo: Intel taglia i prez...
LG C4 da 55'' a 899€ è il top per...
DJI Neo a 159€ è il mini drone pe...
Robot aspirapolvere DREAME D10 Plus Gen ...
A 109€ ha costretto Amazon a nuove scort...
Sbaraglia la concorrenza Intel, questo m...
Giappone all'attacco: ecco il primo wafe...
Cinema in Italia, svolta storica: arriva...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 07:09.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Served by www3v