Jump to content



C++ και έλεγχος δεδομένων.


Dr.Paneas

Recommended Posts

Εχω φτιαξει ενα πολυ απλο προγραμματάκι στο οποιο βάζεις το ονομά σου και το έτος γέννησης, και αυτο με την σειρά του, σου εμφανίζει ποσο χρονών είσαι (κάνοντας 2007-birthYear).

Εχω μια μεταβλητη int birthYear στην οποια εκχωρείται η τιμή της από τον χρήση μέσω της εντολής cin. Ετρεξα το πρόγραμμα και ολα δουλεύουν ρολόι.

Δοκιμασα όμως, αντι να δώσω μια αριθμιτική τιμή στην birthYear, να δώσω ένα χαρακτήρα. πχ a. μετα δοκιμασα aaa. Μετα edf. Το αποτέλεσμα ήταν ότι τελικά είμαι -134514989 χρονών.

Ετσι έφτιαξα το εξής:


#include <string>
#include <iostream>

int main() {
using namespace std;
const int THISYEAR = 2007;
string yourName;
int birthYear;

cout << "What's your name ? " << flush;
getline(cin, yourName);

cout << "What year were you born? ";
cin >> birthYear;

if (THISYEAR-birthYear==-134514989) {
cerr << "This is not valid."
<< " Try again..." << endl;
} else {


cout << "Your name is " << yourName
<< " and you are approximately "
<< (THISYEAR-birthYear)
<< " years old. " << endl;
}
return 0;
}

Τώρα αν δωσω χαρακτήρα αντί για αριθμό, το πρόγραμμα βγαζει το σχετικο μύνημα και τερματίζει. Τι μπορώ να κανω για να μην τερματίζει αλλά να με ξαναρωτάει για δώσω τιμή στην birthYear ;

ΥΣ:Δοκιμασα με do...while() αλλα για καποιο λογο κατι κανω λαθος και γεμίζει το buffer output.

Link to comment
Share on other sites

σιγουρα λυνεται με while

γτ δεν δοκιμαζεις τις βιβλιοθηκες]

simpio,genlib,stdio

νομιζω μια απο αυτες εχει και αυτοματο ελεγχο εισοδου...

δεν θυμαμαι ποια..:tomato: :tomato: :tomato:

edit

αν βαζεις στη λουπα ελεγχου την τιμη -... ως λαθος τοτε μαλλον αυτο φταιει...

βαλτο να βλεπει αν ειναι λογικος αριθμος ,αφου το ευρως δεκτων τιμων ειναι πολυ μικρο.

(1900-2007)

Link to comment
Share on other sites

Ναι βρε συ, αλλα το θεμα να περιοριζει τον εύρος των αριθμων ειναι απλο. Το θέμα είναι να μην επιτρέπει να μπει χαρακτήρας στην αριθμητική μεταβλητή.

Link to comment
Share on other sites

Δες τι λεει αυτος...

http://www.daniweb.com/code/snippet750.html

#include <stdio.h>

#include <conio.h>

#include <iostream.h>

#include <ctype.h>

#include <limits.h>

using namespace std;

int main() {

int number = 0;

cout << "Enter an integer: ";

cin >> number;

cin.ignore(numeric_limits<int>::max(), '\n');

if (!cin || cin.gcount() != 1)

cout << "Not a numeric value.";

else

cout << "Your entered number: " << number;

getch();

return 0;

}

Σε μενα δουλεψε παντως...

Link to comment
Share on other sites

#include <ctype.h>

int isnumber(int c);

Μπορείς επίσης να περνάς τις εισόδους από μία isnumber() για να ελέγχεις

αν αυτό που έδωσε σαν εντολή ο χρήστης είναι αριθμός η αλφαριθμητικό.

Αν όχι, ξαναζητάς είσοδο και πάλι check.

Εναλλακτικά δοκίμασε να διαβάσεις την είσοδο σαν ένα αλφαριθμητικό

και να ελέγξεις κάθε χαρακτήρα αν είναι στα ώρια των αριθμών στο ASCII.

Αν όχι, ξαναζητάς είσοδο και πάλι check.

(ρίξε μια ματιά στους κωδικούς ASCII έναρξη->εκτέλεση->charmap,

είναι στο δεκαεξαδικό οπότε μετέτρεψε τους στο δεκαδικό)

Στάνταρ θα υπάρχουν και άλλοι τρόποι και ίσως πιο εύκολοι-ετοιματζούρικοι αλλά

δε μου έρχεται κάτι άλλο αυτή τη στιγμή.

Link to comment
Share on other sites

Εγώ θα το έκανα κάπως έτσι...


#include <string>
#include <iostream>
#include <[URL=http://www.cplusplus.com/reference/clibrary/cstdlib/]cstdlib[/URL]> //Για να κάνεις calls σε commands από το prompt π.χ. την PAUSE, επίσης έχει την atoi
#pragma argsused

//Ελέγχει εαν το string περιέχει αριθμό
// εαν ναι επιστρέφει true
// αλλιώς επιστρέφει false
bool CheckStr(const std::string& s)
{
for (int i = 0; i < s.length(); i++) {
if (!std::isdigit(s[i]))
return false;
}
return true;
}

//Παίρνει το όνομα
void GetName(std::string& yourName)
{
using namespace std;
cout << "What's your name ? " << flush;
getline(cin, yourName);
}

//Παίρνει την ημ. γέννησης
void GetBirthdate(std::string& birthYear)
{
using namespace std;
cout << "What year were you born? ";
getline(cin, birthYear);
}

int main(int argc, char* argv[])
{
using namespace std;
const int THISYEAR = 2007;
string yourName;
string birthYear;
int intYear;
bool exit = false;

//Μέχρι να δώσει σωστή ημ. ο χρήστης το πρόγραμμα κάνει loop
while (!exit)
{
GetName(yourName); //Παίρνει το όνομα
GetBirthdate(birthYear); //Παίρνει την ημ. γέννησης


if ( CheckStr(birthYear) ) { //Εάν η ημερομηνία είναι σωστή
intYear = atoi(birthYear.c_str() ); //Μετατρέπει το string σε integer
cout << "Your name is " << yourName
<< " and you are approximately "
<< (THISYEAR-intYear)
<< " years old. " << endl;
exit = true;
}
else {
cerr << "This is not valid."
<< " Try again..." << endl;
}
}

system("PAUSE");
return 0;
}

Γενικά είναι καλύτερα να σπας τον κώδικά σου σε κομμάτια και functions έτσι ώστε να διατηρείται καθαρός και να μπορείς να κάνεις εύκολα αλλαγές όπου χρειάζεται...

τώρα ο κώδικας θα λουπάρει συνεχώς μέχρι το exit να γίνει true, το οποίο συμβαίνει μόνο όταν δώσει ο χρήστης σωστή ημ. γέννησης που δεν περιέχει αλφαβητικούς χαρακτήρες...

Edit:

Είναι λάθος να ελέγχεις τον αριθμό με αυτόν τον τρόπο γιατί δεν είναι πάντα "-134514989"... αν κάνεις compile σε 16 ή 32bit αλλάζει... επίσης μπορεί να αλλάξει και οποιοδήποτε άλλο λόγο, εξαρτάται από το σύστημα και η συμπεριφορά του είναι δυναμική... οπότε πρέπει να ελέγχει να μην υπάρχει αυτό που δεν θες...

Link to comment
Share on other sites

Παιζει και σε μενα μια χαρα Jaco. Εχεις δικαιο για τον ελεγχο μου, δεν το σκεφτηκα οτι αλλαζει σε 32/64 bit συστηματα. Να σε ρωτήσω όμως, δεν είναι κάπως λάθος απο λογικής πλευράς να βάζεις μια μεταβλητή string όταν ο ρόλος της είναι να κρατάει αποκλειστικά αριθμούς ; Αυτό αν το πάμε βαθύτερα και γραφεις ενα πολυ μεγαλύτερο πρόγραμμα θα χρειάζεσαι αρκετά περισσότερη RAM από το αν αυτες τις μεταβλητές τις οριζες σαν int. Καταλαβα με ποια λογική το κάνεις και σωστά το κανεις. Αλλα δεν υπάρχει κανένας άλλο τρόπος ;

Δεν καταλαβα τι κανει ο Jonson πιο πανω με το #include <ctype.h>

int isnumber(int c);

και δεν καταλαβα τι κανει o Kalilleo. Αν γινετε να δωσετε ρε guys μια μικρη διευκρινιση...thx.

Link to comment
Share on other sites

Το cin.ignore(numeric_limits<int>::max(), '\n'); τι ακριβως κάνει ;

λεει οτι το ignore υπολογιζει τους αλφαριθμητικους χαρακτήρες και μετα τους απορίπτει.

μετά λεει οτι το numeric_limits<int>::max() επιτρεφει την τελικη max τιμη ενος Integer. Τωρα καπου το χανω το νοημα και δεν καταλαβαινω τι κανει αυτος ο συνδιασμος.....

Link to comment
Share on other sites

Αρχική απάντηση από Dr.Paneas [Σήμερα, στις 13:19]

Παιζει και σε μενα μια χαρα Jaco. Εχεις δικαιο για τον ελεγχο μου, δεν το σκεφτηκα οτι αλλαζει σε 32/64 bit συστηματα. Να σε ρωτήσω όμως, δεν είναι κάπως λάθος απο λογικής πλευράς να βάζεις μια μεταβλητή string όταν ο ρόλος της είναι να κρατάει αποκλειστικά αριθμούς ; Αυτό αν το πάμε βαθύτερα και γραφεις ενα πολυ μεγαλύτερο πρόγραμμα θα χρειάζεσαι αρκετά περισσότερη RAM από το αν αυτες τις μεταβλητές τις οριζες σαν int. διευκρινιση...thx.

και η cin σαν byte array τον παίρνει τον αριθμό και μετά τον μετατρέπειεσωτερικά σε int, οπότε είναι το ίδιο πράγμα αν το κρατήσεις σαν byte array (string) με την διαφορά ότι εσύ το μετατρέπεις σε int μετά από τον έλεγχο σου...

όσο για την μνήμη αυτό ήταν πραγματικά ένα πρόβλημα το οποίο υπήρε κάποτε που τα συστήματα είχαν πολύ περιορισμένη ram (π.χ. 64, 128, 256bit σε διάφορους μcontroler οπότε εκεί μετράγαμε και το τελευταίο bit)... τώρα πια δεν τίθεται τέτοιο θέμα, το μόνο που χρειάζεται είναι προσοχή κατά την εγγραφή των arrays να μην ξεπερνάνε το μέγεθος τους, γιατί τότε έχουμε τα γνωστά memory leaks... επίσης για το συγκεκριμένο παράδειγμα αν χρησιμοποιήσεις string ή byte arrays θα χρειαστείς 4bytes όσα δηλαδή είναι και ένας integer σε 32 bit σύστημα...

όπως και να'χει μην σε ανησυχεί το μέγεθος της μνήμης...

Link to comment
Share on other sites

Εκανα cout << numeric_limits<int>::max(); και ειχα ως output --> 2147483647.

Αυτος ο αριθμος 2^31-1 ειναι ο μέγιστος αριθμός που μπορεί να πάρει μια μεταβλητή signed int ;

To ignore τι κανει το σε συνδιασμο με το numeric_limit ??????? Σβηνει ολο το input ???

Αν καταλαβα καλα :


#include <string>
#include <iostream>
#include <limits>

int main() {
using namespace std;
const int THISYEAR = 2007;
string yourName;
int birthYear,bad_input;

cout << "What's your name ? " << flush;
getline(cin, yourName);

/* Αν το cin διαβάσει κατι που το input δεν μπορει να το
επεξεργαστεί τότε το cin μπαίνει σε "fail" state .
Ολο το input θα αγνοηθεί από το cin μέχρι να καθαριστεί η κατάσταση
fail state.*/

do {
/*Αν ολα πανε καλα και το input δεν μπει σε fail state τοτε
σαφως και δεν θελουμε να εκτελεστει ο βρογχος. 1=true, 0=false */
bad_input=0;
cout <<"\nWhat year were you born :" << flush ;
cin >> birthYear;
if(!cin.good()) // Εαν το input δεν ειναι σωστό
{
/*Επειδή το input έχει προβλημα, πρέπει να ξανα διαβάσουμε
το birthYear, αυτό θα γίνει αν δωσουμε 1 στην μεταβλητη που
καναμε initialization με 0 νωριτερα.ωστε να επαναλαμβάνεται
ο βρογχος */
bad_input=1;
cin.clear(); //Καθαρίζει την fail state

/*Τωρα θα σβήσουμε το input που προκαλεσε το προβλημα */
cin.ignore(numeric_limits<streamsize>::max(),'\n');
cout << "This is not valid value" << endl;
}
}while(bad_input);

cout << "Your name is " << yourName
<< " and you are approximately "
<< (THISYEAR-birthYear)
<< " years old. " << endl;

return 0;
}

Αλλα δεν εχω κατανοησει πληρως τα πραγματα...

Ενας δεύτερος τρόπος:


#include <string>
#include <iostream>
#include <limits>

int main() {
using namespace std;
const int THISYEAR = 2007;
string yourName;
int birthYear;

cout << "What's your name ? " << flush;
getline(cin, yourName);

/* Αν το cin διαβάσει κατι που το input δεν μπορει να το
επεξεργαστεί τότε το cin μπαίνει σε "fail" state .
Ολο το input θα αγνοηθεί από το cin μέχρι να καθαριστεί η κατάσταση
fail state.*/

cout <<"What year were you born? " << flush;
while(!(cin>>birthYear)) //Οσο το input δεν ειναι σωστό
{
cin.clear(); //βγαζει το stream απο την θεση fail state

/*Σβήνει απο το stream το input που προκάλεσε το προβλημα */
cin.ignore(numeric_limits<streamsize>::max(),'\n');
// Πως διαλο το κανει αυτο ; Αγνοόντας τον μεγιστο αριθμο ;WTF ?

cout << "No valid value. ";
cout <<"What year were you born? " << flush;
}



cout << "Your name is " << yourName
<< " and you are approximately "
<< (THISYEAR-birthYear)
<< " years old. " << endl;

return 0;
}

Επειδη οι παραπανω δυο τροποι εχουν προβλημα με το direct αριθμητικο input καλυτεροι ειναι οι εμεσοι τροποι.

Οπως:


#include <string>
#include <iostream>
#include <cstdlib>

int main() {
using namespace std;
const int THISYEAR = 2007;
string yourName;
int birthYear;
char temp[100];

cout << "What's your name ? " << flush;
getline(cin, yourName);

do {
cout <<"What year were you born? " << flush;
cin.getline(temp,100); //την αποθηκευει στο temp

/*Αντιγράφει το temp στο birthYear και αν δωσω
αλφαριθμητικό, τότε το μετατρέπει σε ακέραιο
και τελικα η birthYear εχει την τιμή 0. */
birthYear=atoi(temp);
if (birthYear==0) {
cout << "Invalid valude..." << flush;
}
} while(birthYear==0);




cout << "Your name is " << yourName
<< " and you are approximately "
<< (THISYEAR-birthYear)
<< " years old. " << endl;

return 0;
}

και με while αλλα ειναι βλακεια..


#include <string>
#include <iostream>
#include <cstdlib>

int main() {
using namespace std;
const int THISYEAR = 2007;
string yourName;
int birthYear;
char temp[100];

cout << "What's your name ? " << flush;
getline(cin, yourName);

cout <<"What year were you born? " << flush;
cin.getline(temp,100); //Το αποθηκευει στο temp

/*Αποθηκεύει την temp στο birthYear μετατρεποντας την σε int.
Αν εχει μεσα εστω και εναν αλαφαριθμητικο χαρακτηρα
η birthYear θα παρει την τιμή 0 */
birthYear = atoi(temp);

while(birthYear==0)
{
cout << "Invalid value..."
<< "What year were you born? " << flush;
cin.getline(temp,100); //Το αποθηκευει στο temp
birthYear = atoi(temp);
}




cout << "Your name is " << yourName
<< " and you are approximately "
<< (THISYEAR-birthYear)
<< " years old. " << endl;

return 0;
}

Δεν ξερω ομως αν υπαρξει προβλημα με το temp που εχει μονο 100.....

Link to comment
Share on other sites

Ισως η καλυτερη λυση που μου προτεινε ενα παιδι (George απο LinuxFormat) και την αλλαξα λιγο, ειναι:


#include <string>
#include <iostream>
#include <sstream> // for istringstream convert()
using namespace std;

int main()
{
const int THISYEAR = 2007;
string yourName;
int birthYear;
string birth; //για το έτος γέννησης

cout << "What's your name ? " << flush;
getline(cin,yourName);
for(;1;) {
cout << "What year were you born? ";
getline(cin,birth);
// μετατροπή string -----> int
istringstream convert(birth);
// τοποθέτηση στην int birthYear
convert >> birthYear;
// αν δεν πετύχει σημαίνει ότι δεν είναι αριθμός
if(!convert {
cout << " This is not valid.Try again...." << endl;
continue;
} else {
break;
}
}

cout << "Your name is " << yourName
<< " and you are approximately "
<< (THISYEAR-birthYear)
<< " years old. " << endl;



return 0;
}

Και η ερωτηση μου ειναι η εξης: Ποιος τροπος ειναι ο καλυτερος ; Αν κανω istringstream convert() θα πρεπει να εχω συν μια μεταβλητη στην οποια θα αποθηκευεται το string και μετα μια αλλη στην οποια θα αποθηευγεται το int.

Με τον αλλο τροπο που μπαινει σε fail state, χρησιμοποιωντας τον βρογχο while (οχι τον Do while με την βοηθητικη μεταβλητη bad_input) δεν χρησιμοποιώ άλλη μεταβλητη. Αρα κερδιζω σε RAM.

Ποιος τρόπος προτιμάτε σήμερα; Αν θελετε ενας εμπειρος προγραμματιστης σε ενα μεγαλο προγραμμα για Windows/Linux/Mac, ποια μεθοδο θα εφαρμοζε ;

Link to comment
Share on other sites

Από οτι ρώτησα μερικά άτομα που ασχολούνται με C++ μου ειπαν οτι δεν υπαρχει προβλημα να χρησιμοποιουμε την μεθοδο που κανει μετατροπη το string σε integer. Αλλα με αυτον τον τροπο (δηλαδη με atoi() function ) δεν ελεγχεται το buffer overflow αλλα και οτι δεν συνηθιζεται να γινεται ετσι στην C++ αλλά κυριως στην C γινεται αυτο.

Καλύτερα να το κανω ετσι:


#include <string>
#include <iostream>
#include <limits>

#define THISYEAR 2007


int main() {

using namespace std;
string yourName;
int birthYear;

cout << "What's your name ? " << flush;
cin >> yourName;

cout << "What year were you born? ";
cin >> birthYear;

while(!cin.good() || birthYear <= 0 || birthYear >= THISYEAR) {
cin.clear( );
cin.ignore( numeric_limits<streamsize>::max( ), '\n');
cout << "No Valid value. What year were you born? " << flush;
cin >> birthYear;
}



cout << "Your name is " << yourName
<< " and you are approximately "
<< (THISYEAR-birthYear)
<< " years old. " << endl;

return 0;
}

Αυτα...

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Δημιουργία...

Important Information

Ο ιστότοπος theLab.gr χρησιμοποιεί cookies για να διασφαλίσει την καλύτερη εμπειρία σας κατά την περιήγηση. Μπορείτε να προσαρμόσετε τις ρυθμίσεις των cookies σας , διαφορετικά θα υποθέσουμε ότι είστε εντάξει για να συνεχίσετε.