Dr.Paneas Δημοσιεύτηκε Νοέμβριος 24, 2007 #1 Κοινοποίηση Δημοσιεύτηκε Νοέμβριος 24, 2007 Εχω φτιαξει ενα πολυ απλο προγραμματάκι στο οποιο βάζεις το ονομά σου και το έτος γέννησης, και αυτο με την σειρά του, σου εμφανίζει ποσο χρονών είσαι (κάνοντας 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 More sharing options...
oxide Νοέμβριος 24, 2007 #2 Κοινοποίηση Νοέμβριος 24, 2007 σιγουρα λυνεται με while γτ δεν δοκιμαζεις τις βιβλιοθηκες] simpio,genlib,stdio νομιζω μια απο αυτες εχει και αυτοματο ελεγχο εισοδου... δεν θυμαμαι ποια.. :tomato: edit αν βαζεις στη λουπα ελεγχου την τιμη -... ως λαθος τοτε μαλλον αυτο φταιει... βαλτο να βλεπει αν ειναι λογικος αριθμος ,αφου το ευρως δεκτων τιμων ειναι πολυ μικρο. (1900-2007) Link to comment Share on other sites More sharing options...
Dr.Paneas Νοέμβριος 24, 2007 Author #3 Κοινοποίηση Νοέμβριος 24, 2007 Ναι βρε συ, αλλα το θεμα να περιοριζει τον εύρος των αριθμων ειναι απλο. Το θέμα είναι να μην επιτρέπει να μπει χαρακτήρας στην αριθμητική μεταβλητή. Link to comment Share on other sites More sharing options...
jogi Νοέμβριος 24, 2007 #4 Κοινοποίηση Νοέμβριος 24, 2007 try - catch and exception handling...? Link to comment Share on other sites More sharing options...
kallileo Νοέμβριος 24, 2007 #5 Κοινοποίηση Νοέμβριος 24, 2007 Δες τι λεει αυτος...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 More sharing options...
oxide Νοέμβριος 24, 2007 #6 Κοινοποίηση Νοέμβριος 24, 2007 εχεις δικιο εκανα λαθος...αλλα αυτο που σου ειπα για τις βιβλιοθηκες ισχυει(με μια μικρη επιφυλαξη) Link to comment Share on other sites More sharing options...
johnson Νοέμβριος 24, 2007 #7 Κοινοποίηση Νοέμβριος 24, 2007 #include <ctype.h>int isnumber(int c);Μπορείς επίσης να περνάς τις εισόδους από μία isnumber() για να ελέγχειςαν αυτό που έδωσε σαν εντολή ο χρήστης είναι αριθμός η αλφαριθμητικό.Αν όχι, ξαναζητάς είσοδο και πάλι check.Εναλλακτικά δοκίμασε να διαβάσεις την είσοδο σαν ένα αλφαριθμητικόκαι να ελέγξεις κάθε χαρακτήρα αν είναι στα ώρια των αριθμών στο ASCII.Αν όχι, ξαναζητάς είσοδο και πάλι check.(ρίξε μια ματιά στους κωδικούς ASCII έναρξη->εκτέλεση->charmap,είναι στο δεκαεξαδικό οπότε μετέτρεψε τους στο δεκαδικό)Στάνταρ θα υπάρχουν και άλλοι τρόποι και ίσως πιο εύκολοι-ετοιματζούρικοι αλλάδε μου έρχεται κάτι άλλο αυτή τη στιγμή. Link to comment Share on other sites More sharing options...
HotPeanut Νοέμβριος 25, 2007 #8 Κοινοποίηση Νοέμβριος 25, 2007 Αρχική απάντηση από jogi [Χθες, στις 17:36] try - catch and exception handling...? Υπάρχει αυτό στη C++? Εγώ νόμιζα ότι υπάρχει στη Java. Link to comment Share on other sites More sharing options...
soki Νοέμβριος 25, 2007 #9 Κοινοποίηση Νοέμβριος 25, 2007 εφοσον βγαζει αρνητικο μπορεις να βαλεις εναν ελεγχο για αρνητικο αριθμο οταν κανεις την αφαιρεσηif (THISYEAR-birthYear<0) { cerr << "This is not valid." << " Try again..." << endl; ...... Link to comment Share on other sites More sharing options...
Jaco Νοέμβριος 25, 2007 #10 Κοινοποίηση Νοέμβριος 25, 2007 Εγώ θα το έκανα κάπως έτσι...#include <string>#include <iostream>#include <[URL=http://www.cplusplus.com/reference/clibrary/cstdlib/]cstdlib[/URL]> //Για να κάνεις calls σε commands από το prompt π.χ. την PAUSE, επίσης έχει την atoi#pragma argsused//Ελέγχει εαν το string περιέχει αριθμό// εαν ναι επιστρέφει true// αλλιώς επιστρέφει falsebool 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 More sharing options...
oxide Νοέμβριος 25, 2007 #11 Κοινοποίηση Νοέμβριος 25, 2007 Jaco ωραιος κωδικος ...πολυ σωστος! Link to comment Share on other sites More sharing options...
Jaco Νοέμβριος 25, 2007 #12 Κοινοποίηση Νοέμβριος 25, 2007 Αρχική απάντηση από oxide [Σήμερα, στις 12:17] Jaco ωραιος κωδικος ...πολυ σωστος! thanks... αλλά σίγουρα μπορεί να γίνει γρηγορότερος και μικρότερος... παίρνει και άλλο optimize... Link to comment Share on other sites More sharing options...
Dr.Paneas Νοέμβριος 25, 2007 Author #13 Κοινοποίηση Νοέμβριος 25, 2007 Παιζει και σε μενα μια χαρα 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 More sharing options...
Dr.Paneas Νοέμβριος 25, 2007 Author #14 Κοινοποίηση Νοέμβριος 25, 2007 Το cin.ignore(numeric_limits<int>::max(), '\n'); τι ακριβως κάνει ;λεει οτι το ignore υπολογιζει τους αλφαριθμητικους χαρακτήρες και μετα τους απορίπτει.μετά λεει οτι το numeric_limits<int>::max() επιτρεφει την τελικη max τιμη ενος Integer. Τωρα καπου το χανω το νοημα και δεν καταλαβαινω τι κανει αυτος ο συνδιασμος..... Link to comment Share on other sites More sharing options...
Jaco Νοέμβριος 25, 2007 #15 Κοινοποίηση Νοέμβριος 25, 2007 Αρχική απάντηση από 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 More sharing options...
Dr.Paneas Νοέμβριος 25, 2007 Author #16 Κοινοποίηση Νοέμβριος 25, 2007 Εκανα 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 More sharing options...
Dr.Paneas Νοέμβριος 25, 2007 Author #17 Κοινοποίηση Νοέμβριος 25, 2007 Ισως η καλυτερη λυση που μου προτεινε ενα παιδι (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 More sharing options...
Dr.Paneas Νοέμβριος 25, 2007 Author #18 Κοινοποίηση Νοέμβριος 25, 2007 Από οτι ρώτησα μερικά άτομα που ασχολούνται με C++ μου ειπαν οτι δεν υπαρχει προβλημα να χρησιμοποιουμε την μεθοδο που κανει μετατροπη το string σε integer. Αλλα με αυτον τον τροπο (δηλαδη με atoi() function ) δεν ελεγχεται το buffer overflow αλλα και οτι δεν συνηθιζεται να γινεται ετσι στην C++ αλλά κυριως στην C γινεται αυτο.Καλύτερα να το κανω ετσι:#include <string>#include <iostream>#include <limits>#define THISYEAR 2007int 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 More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.