ΕΛΛΗΝΙΚΗ ΔΗΜΟΚΡΑΤΙΑ Ανώτατο Εκπαιδευτικό Ίδρυμα Πειραιά Τεχνολογικού Τομέα Δομημένος Προγραμματισμός Ενότητα 3: Είσοδος και έξοδος Κουκουλέτσος Κώστας Τμήμα Μηχανικών Ηλεκτρονικών Υπολογιστικών Συστημάτων
Άδειες Χρήσης Το παρόν εκπαιδευτικό υλικό υπόκειται σε άδειες χρήσης Creative Commons. Για εκπαιδευτικό υλικό, όπως εικόνες, που υπόκειται σε άλλου τύπου άδειας χρήσης, η άδεια χρήσης αναφέρεται ρητώς.
Χρηματοδότηση Το παρόν εκπαιδευτικό υλικό έχει αναπτυχθεί στα πλαίσια του εκπαιδευτικού έργου του διδάσκοντα. Το έργο «Ανοικτά Ακαδημαϊκά Μαθήματα στο Ανώτατο Εκπαιδευτικό Ίδρυμα Πειραιά Τεχνολογικού Τομέα» έχει χρηματοδοτήσει μόνο τη αναδιαμόρφωση του εκπαιδευτικού υλικού. Το έργο υλοποιείται στο πλαίσιο του Επιχειρησιακού Προγράμματος «Εκπαίδευση και Δια Βίου Μάθηση» και συγχρηματοδοτείται από την Ευρωπαϊκή Ένωση (Ευρωπαϊκό Κοινωνικό Ταμείο) και από εθνικούς πόρους.
Σκοποί ενότητας Oι διδακτικοί σκοποί της ενότητας είναι ο σπουδαστής: Να μπορεί να ορίζει τον τρόπο εισόδου και εξόδου μεταβλητών και τιμών Να κατανοήσει την χρήση των χαρακτήρων διαφυγής Να μάθει πως γίνεται μετατροπή του τύπου τιμών και μεταβλητών Να κατανοήσει λάθη που πιθανόν εμφανίζονται λόγω στρογγυλοποίησης Να εξοικειωθεί με την χρήση των προσδιοριστών εμφάνισης Να γνωρίσει τις ιδιαιτερότητες της εντολής scanf()
Περιεχόμενα ενότητας Εμφάνιση στην οθόνη- συνάρτηση printf() Προσδιοριστές εμφάνισης Ακολουθίες διαφυγής Εμφάνιση ειδικών χαρακτήρων Εμφάνιση μεταβλητών Λάθη στρογγυλοποίησης (round off errors) Flags (σημαίες) με την printf() Μετατροπή τύπου - Type casting Είσοδος δεδομένων - Scanf() Scanf() και πληκτρολόγιο Συνάρτηση fflush() Ασκήσεις
Εμφάνιση στην οθόνη- συνάρτηση printf() (1/2) Η γλώσσα C εμφανίζει δεδομένα στην οθόνη με την χρήση έτοιμων συναρτήσεων που ανήκουν σε μία βιβλιοθήκη. Μία τέτοια συνάρτηση είναι η printf( ). Ο γενικός τύπος της εντολής είναι printf ( "<format string>", <list of variables>) printf ( "<συμβολοσειρά μορφοποίησης>", <λίστα μεταβλητών>)
Εμφάνιση στην οθόνη- συνάρτηση printf() (2/2) Παράδειγμα» int x=5, y=10;» printf ("To x= %d To y= %d \n", x, y); Η συμβολοσειρά (ή αλφαριθμητικό) μορφοποίησης μπορεί να περιέχει 1) προσδιοριστές εμφάνισης (specifiers) 2) χαρακτήρες και 3) ακολουθίες διαφυγής
Προσδιοριστές εμφάνισης (1/2) Οι πιο συνηθισμένοι προσδιοριστές εμφάνισης (specifiers) που καθορίζουν τον τρόπο εμφάνισης των μεταβλητών είναι %d ή %i για εμφάνιση ακεραίων τιμών %f, %lf για εμφάνιση πραγματικών τιμών (float και double) %e ή %E για εμφάνιση πραγματικού αριθμού σε επιστημονική μορφή
Προσδιοριστές εμφάνισης (2/2) %c %s για εμφάνιση ενός χαρακτήρα για εμφάνιση χαρακτήρων (συμβολοσειράς) %x ή %Χ για εμφάνιση ακεραίου σε 16δικη μορφή (με μικρά ή κεφαλαία) %o για εμφάνιση ακεραίου σε οκταδική μορφή Εκτός των ανωτέρω υπάρχουν και άλλοι προσδιοριστές
Παράδειγμα (1/2) Εκτός από τον specifier όλα τα άλλα στοιχεία είναι προαιρετικά. Οποιοιδήποτε άλλοι χαρακτήρες μπορεί να προστεθούν μέσα στη συμβολοσειρά διαμόρφωσης εκτός από τους παραπάνω προσδιοριστές εμφάνισης. Αυτοί εμφανίζονται στην οθόνη όπως είναι γραμμένοι.
Παράδειγμα (2/2) Η γραμμή» printf ( "%d, %o and %x\n", 27, 27, 27 ) ; εκτυπώνει» 27, 33 and 1b. Η γραμμή» printf("%d %o %x\n",50,050,0x50); εκτυπώνει» 50 50 50 διότι όποιοι αριθμοί έχουν 0 θεωρούνται οκταδικοί ενώ όποιοι έχουν 0x θεωρούνται δεκαεξαδικοι. Η γραμμή» printf("%d %o %x\n",50,50,50);» εκτυπώνει τον αριθμό 50 στο δεκαδικό το οκταδικό και το δεκαεξαδικό σύστημα» 50 62 32
Ακολουθίες διαφυγής Οι ακολουθίες διαφυγής δεν εμφανίζονται αλλά πραγματοποιούν μία άλλη λειτουργία δηλαδή διαφεύγουν από την συνηθισμένη εμφάνιση στη οθόνη. Η ακολουθία αρχίζει με τον χαρακτήρας διαφυγής που είναι η ανάποδη κάθετο (backslash) και ένα συγκεκριμένο χαρακτήρα.
Εμφάνιση ειδικών χαρακτήρων \\ - print a backslash \" - print a double quote \ - print a single quote %% - print a percent sign Παράδειγμα
Εμφάνιση μεταβλητών (1/6) Ασυμβατότητα specifiers και λίστας Αν τα specifiers είναι περισσότερα από τις μεταβλητές τότε εμφανίζονται τυχαίες τιμές (σκουπίδια) Αν τα specifiers είναι λιγότερα τότε εμφανίζονται μόνο οι τιμές των μεταβλητών που αντιστοιχούν στα specifiers» int main()» {» int d1,d2,d3;» d1=11; d2=22; d3=33;»» printf("%d %d %d\n\n",d1,d2);» printf("%d %d \n",d1,d2,d3);»» system("pause");» return 0;» }
Εμφάνιση μεταβλητών (2/6) Είναι δυνατό να καθοριστεί τόσο το συνολικό πλήθος των ψηφίων, που θα εμφανιστούν στην οθόνη (δηλαδή το πλάτος του πεδίου που θα καταλάβει ο αριθμός για ακεραίους και πραγματικούς) Πλάτος πεδίου εμφάνισης (width) Αν το πλάτος είναι περισσότερο από τους χαρακτήρες του αριθμού τότε προστίθενται κενά από τα αριστερά προς τα δεξιά ώστε η συνολική εμφάνιση να είναι ίση με το πλάτος που καθορίζεται Αν το πλάτος που καθορίζεται είναι λιγότερο από χώρος που χρειάζεται ο αριθμός τότε ο αριθμός που καθορίζει το πλάτος δεν λαμβάνεται υπόψη.
Εμφάνιση μεταβλητών (3/6)» int m=1234;» printf("\n\n\n1234567890\n");» printf("%10d\n",m);» printf("%9d\n",m);» printf("%8d\n",m);» printf("%7d\n",m);» printf("%4d\n",m);» printf("%3d\n",m);
Εμφάνιση μεταβλητών (4/6) Είναι δυνατό να καθοριστεί και το πλήθος των δεκαδικών (ακρίβεια) στην περίπτωση πραγματικών αριθμών Ακρίβεια εμφάνισης (precision) Για τους πραγματικούς η εξ ορισμού (by default) ακρίβεια είναι 6 δεκαδικά ψηφία Το πλάτος του αριθμού καθορίζεται με ένα αριθμό αμέσως μετά το % H ακρίβεια καθορίζεται με την τελεία ακολουθημένη από τον αριθμό που καθορίζει την ακρίβεια.
Εμφάνιση μεταβλητών (5/6)» int k=1234;» double z=6789.111;» printf("%10d\n",k);» printf("z= %12f \n",z);» printf("z= %f \n",z);» printf("z= %12.3f\n",z);» printf("z= %6f\n",z);
Εμφάνιση μεταβλητών (6/6) Είναι δυνατό να καθοριστεί και το πλήθος των δεκαδικών (ακρίβεια) στην περίπτωση πραγματικών αριθμών Αν δεν υπάρχει αριθμός τότε εμφανίζεται η τιμή χωρίς δεκαδικά ψηφία Η τιμή που εμφανίζεται στρογγυλοποιείται προς τα κάτω αν το πρώτο ψηφίο που αποκόπτεται είναι <=4 και προς τα πάνω σε αντίθετη περίπτωση
Παράδειγμα
Λάθη στρογγυλοποίησης (round off errors) (1/3) To παρακάτω πρόγραμμα εμφανίζει λάθος τιμή» double p=10.77;» int k=100*p;» printf("k= %d\n",k);» Κανονικά θα έπρεπε να εμφανιστεί το 1077 εμφανίζεται το 1076 Στο υπολογιστή οι αριθμοί αναπαριστώνται στο δυαδικό σύστημα Στο δυαδικό σύστημα δεν υπάρχει ακριβής αναπαράσταση του αριθμού 10.77. Ο συγκεκριμένος αριθμός αναπαρίσταται με κάτι λιγότερο από 10.77 Κάτι ανάλογο γίνεται και στο δεκαδικό σύστημα με τον αριθμό 1/3 Ο πολλαπλασιασμό 100*10.77 εμφανίζεται να είναι 10.76 για αυτό τον λόγο
Λάθη στρογγυλοποίησης (round off errors) (2/3) Ακόμη και μία απλή εκχώρηση ίδιου δεκαδικού αριθμού σε float και σε double παρουσιάζει διαφορές λόγω της ακρίβειας μεταξύ των δύο τύπων Το αποτέλεσμα εμφάνιση είναι διαφορετικό
Λάθη στρογγυλοποίησης (round off errors) (3/3) Για πραγματικές μεταβλητές καλό είναι να χρησιμοποιείται ο τύπος double και όχι ο float γιατί ο χειρισμός των δεκαδικών ψηφίων και επομένως η ακρίβεια του αριθμού και των υπολογισμών δεν είναι ο αναμενόμενος Παρατηρήστε την διαφορά στο αποτέλεσμα μεταξύ των δύο δηλώσεων μίας μεταβλητής στην οποία εκχωρείται ο ίδιος αριθμός και μετά πολλαπλασιάζεται με το 111
Flags (σημαίες) με την printf() O τρόπος εμφάνισης των τιμών μπορεί να αλλαχθεί με την χρήση flags. Στον παρακάτω πίνακα εμφανίζονται μερικές από τις χρήσεις που μπορεί να κάνει ο προγραγραμματιστής με μία σημαία Σημαία (flag) Αλλαγή - Στοιχίζει αριστερά την τιμή 0 Το πεδίο εμφάνισης γεμίζει με 0 αντί για κενά + Εμφανίζεται και το πρόσημο του αριθμού Κενός χαρακτήρας Οι θετικοί αριθμοί αρχίζουν με κενό # Σε συνδυασμό με το ο (οκταδικός αριθμός) το πρώτο ψηφίο είναι πάντα 0 Σε συνδυασμό με το χ ή το Χ θα εμφανίζει το 0χ ή το 0Χ σε μη μηδενικές τιμές
Παραδείγμα με flags (1/2) Τι εμφανίζει το παρακάτω πρόγραμμα» printf ("Kena prin: %10d\n", 1234);» printf ("Miden prin: %010d \n", 1234);» printf ("Emfanisi arithmon se diafora sistimata\n");» printf( "%d %x %o %#x %#o \n",100, 100, 100, 100, 100);
Παραδείγμα με flags (2/2)» printf("%-8d\n",1234);» printf("%8d\n",1234);» printf("%+8d\n",1234);» printf("%-+8d\n",1234);»» printf("\n\n\n\n");» int y=17;» printf("%8d\n",y);» printf("% 8d\n",y);» printf("%#o\n",y);» printf("%#0x\n",y);» printf("%#20o\n",y);» printf("%#20x\n",y);
Μετατροπή τύπου - Type casting Οι πράξεις με τους περισσότερους δυαδικούς τελεστές (όπως + - * / %) απαιτείται οι τελεστέοι να είναι του ίδιου τύπου. Όταν είναι διαφορετικού τύπου μεταγλωττιστής αναλαμβάνει αυτόματα την μετατροπή τους ώστε να είναι ίδιου τύπου και συγκεκριμένα μετατρέπεται ο τύπος με το μικρότερο εύρος τιμών. Οι μετατροπές τύπων μπορεί να είναι είτε υπονοούμενες (implicit conversions), είτε να προσδιορίζονται ρητά από τον προγραμματιστή (explicit conversions). Υπονοούμενες μετατροπές γίνονται και κατά την εκχώρηση μεταβλητών
Μετατροπές (Implicit) Implicit conversions: Αυτού του τύπου τις μετατροπές αναλύθηκαν και σε προηγούμενη διάλεξη 10/4 η πράξη έχει σαν αποτέλεσμα το 2 10./4, 10/4., 10./4. έχει σαν αποτέλεσμα το 2.5 int i=3.5; float f=3/2; (το i έχει τιμή 3 ενώ το f τιμή 1.000000) int κ=10./4; (το κ έχει τιμή 2) float m=10/4; (το m έχει τιμή 2.000000)
Μετατροπές (explicit) Explicit conversion (type casting) (float)2 μετατρέπει το 2 σε πραγματικό int a=5; float x=(float)a/2; Η τιμή του a μετατρέπεται σε πραγματικό για τις ανάγκες τις πράξης (προσωρινά) δηλαδή ο a εξακολουθεί και έχει ακέραια τιμή Παράδειγμα εμφανίζει»
Παραδείγματα Τι θα τυπώσει το παρακάτω πρόγραμμα (Implicit conversions) Τι θα τυπώσει το παρακάτω πρόγραμμα (type casting- Explicit conversions)
Είσοδος δεδομένων - Scanf() (1/2) H συνάρτηση αυτή χρησιμεύει για την είσοδο δεδομένων από το πληκτρολόγιο. Η γλώσσα C θεωρεί τις συσκευές όπως το πληκτρολόγιο την οθόνη σαν αρχεία. Το πληκτρολόγιο σαν αρχείο ονομάζεται stdin (standard input stream) και με την εκτέλεση του προγράμματος το αρχείο αυτό διατίθεται στην γλώσσα για είσοδο δεδομένων από πληκτρολόγιο. Η μορφή της εντολής είναι ίδια με την printf» scanf ( "<format string>", <list of address variables>)» scanf( "<συμβολοσειρά μορφοποίησης>", <διευθύνσεις μεταβλητών>) Η συνάρτηση scanf διαβάζει τα δεδομένα από το stdin σύμφωνα με τον τρόπο που υπαγορεύει η συμβολοσειρά μορφοποίησης Τα δεδομένα αποστέλλονται στην συνάρτηση με το πάτημα του Enter
Είσοδος δεδομένων - Scanf() (2/2) Η συμβολοσειρά (ή αλφαριθμητικό) μορφοποίησης μπορεί να περιέχει 1.προσδιοριστές εμφάνισης και 2.χαρακτήρες Οι περισσότεροι προσδιοριστές εμφάνισης είναι ίδιοι με αυτούς της εντολής printf (%d %f %c κλπ) Οι διευθύνσεις μεταβλητών είναι διευθύνσεις στην μνήμη του υπολογιστή που θα αποθηκευτούν οι μεταβλητές. Για να καθοριστεί η διεύθυνση στην μνήμη που θα αποθηκευτεί η τιμή της μεταβλητής χρησιμοποιείται ο τελεστής διεύθυνσης &
Παράδειγμα 1 (1/2)» scanf( %d, &a); Περιμένει ένα ακέραιο αριθμό από το πληκτρολόγιο που θα υποθηκευτεί στην διεύθυνση &a της μεταβλητής a» int a,b;» printf(" Dose 2 aritmous");» scanf("%d %d",&a,&b);» printf("%d %d",a, b);
Παράδειγμα 1 (2/2) Στo παραπάνω παράδειγμα τα δεδομένα που εισάγονται είναι περισσότερα από ένα τότε τα δεδομένα αυτά εισάγονται με ένα ή περισσότερα κενά (ή αλλαγές γραμμών ή ακόμη και tabs) μεταξύ τους τα οποία και αγνοούνται από την scanf(). Aν ο χρήστης εισάγει μόνο ένα δεδομένο και πατήσει enter η scanf περιμένει και τα υπόλοιπα δεδομένα που περιγράφονται στην λίστα μεταβλητών Γίνεται αντιστοίχιση των προσδιοριστών της scanf με τις διευθύνσεις των μεταβλητών που περιγράφονται Δηλαδή το πρόγραμμα περιμένει την εισαγωγή όλων των δεδομένων αγνοώντας κενά, αλλαγές γραμμών και tabs. Γενικά η scanf διαχωρίζει τα δεδομένα με τους λεγόμενους whitespace characters που είναι το κενό, ο στηλοθέτης και το enter
Παράδειγμα 2 (1/2) Προσοχή στην συμβολοσειρά μορφοποίησης: Οι χαρακτήρες μέσα στην συμβολοσειρά μορφοποίησης έχουν σαν αποτέλεσμα η γλώσσα C να περιμένει να διαβάσει αυτούς τους χαρακτήρες και να τους αγνοήσει. Καλό είναι να μην υπάρχουν άλλοι χαρακτήρες εκτός από τα κενά γιατί σε περίπτωση μη εισαγωγής αυτών των χαρακτήρων από το πληκτρολόγια η συνάρτηση scanf τερματίζει με απρόβλεπτα αποτελέσματα
Παράδειγμα 2 (2/2) Παράδειγμα» scanf( %d, %d, &a, &b ); διαβάζει ένα ακέραιο διαβάζει και περιμένει την εισαγωγή ενός κόμματος για να μετά διαβάζει μετά ένα δεύτερο ακέραιο. Αν δεν βρεθεί κόμμα η εντολή τερματίζει και ο δεύτερος αριθμός έχει απρόβλεπτη τιμή. Παράδειγμα» int x, y ;» printf ( "Dose 2 akeraious\n" ) ;» scanf ( " %d, %d", &x, &y ) ;» printf ( "a= %d b=%d\n", x, y ) ;
Παράδειγμα 3 Στο παρακάτω παράδειγμα ο προγραμματιστής δεν χρησιμοποιεί σωστά την συνάρτηση και παραλείπει να βάλει τον τελεστή διεύθυνσης στην μεταβλητή Παράδειγμα» int x;» printf ( "Dose akeraio\n" ) ;» scanf ( "%d", x ) ;» printf ("x= %d y=%d\n", x,y );
Παράδειγμα 4 (1/2) Η σωστή είσοδος δεδομένων τύπου float γίνεται με το %f ενώ για δεδομένα τύπου double γίνεται με το %lf
Παράδειγμα 4 (2/2) Η τιμή του y είναι λάθος διότι εισήχθη με το %f ενώ θα έπρεπε να γίνει χρήση του %lf Η εκτύπωση μπορεί να γίνει σωστά και με τους δύο προσδιοριστές Όπως είναι κατανοητό η scanf έχει πολλές ιδιαιτερότητες στην χρήση της και κρύβει παγίδες για τον προγραμματιστή. Η τιμή που αποθηκεύεται με την χρήση της πρέπει να ελέγχεται ώστε να είναι σύμφωνη με τις απαιτήσεις του προγράμματος
Scanf() και πληκτρολόγιο Η scanf έχει την ιδιαιτερότητα να μην διαβάζει τον χαρακτήρα νέας γραμμή. Επομένως όταν ο χρήστης έχει χρησιμοποιήσει την scanf και πατήσει το enter αφού πληκτρολογήσει τα δεδομένα που διαβάζει η scanf τότε στον buffer (μία ενδιάμεση μνήμη) του πληκτρολογίου έχει μείνει ο χαρακτήρας αλλαγής γραμμής που έχει πατήσει ο χρήστης μετά την εισαγωγή δεδομένων. Εάν κατόπιν υπάρχει μία εντολή scanf() που διαβάζει χαρακτήρα στην ουσία θα διαβάσει την αλλαγή γραμμής που έχει εισάγει ο χρήστης μετά την πληκτρολόγηση των δεδομένων που αντιστοιχούν στην προηγούμενη εντολή scanf(). Για την αποφυγή αυτού του προβλήματος χρησιμοποιείται η συνάρτηση fflush() που καθαρίζει ότι έχει μείνει στον buffer και έχει σαν παράμετρο το stdin
Συνάρτηση fflush() Εδώ σαν παράμετρος της fflush χρησιμοποιείται το stdin που αφορά το standard input device δηλαδή το πληκτρολόγιο. Το παρακάτω παράδειγμα χωρίς την εντολή fflush (που παρουσιάζεται σαν σχόλιο) έχει περίεργα αποτελέσματα.
Άσκηση 1 Να αρχικοποιούνται δύο ακέραιες μεταβλητές σε ένα πρόγραμμα και κατόπιν να εμφανίζεται το άθροισμα η διαφορά το γινόμενο και το υπόλοιπο των δύο μεταβλητών. 1 ος τρόπος 2 ος τρόπος (με χρήση μεταβλητών)
Άσκηση 2 Να γραφεί πρόγραμμα που να εμφανίζει το άθροισμα των ακεραίων και το άθροισμα των δεκαδικών τμημάτων δύο πραγματικών αριθμών. Οι πραγματικοί αριθμοί να εισάγονται από το πληκτρολόγιο.
Άσκηση 3 Να γραφεί πρόγραμμα που, αφού εισαχθούν 3 πραγματικές τιμές και αποθηκευτούν σε 3 μεταβλητές, να αλλάζει τις τιμές κατά μία θέση προς τα αριστερά δηλαδή αν οι τιμές των μεταβλητών είναι αρχικά 1,2,3 μετά να είναι 2,3,1
Άσκηση 4 Να γραφεί πρόγραμμα που εμφανίζει το υπόλοιπο ενός πραγματικού αριθμού με ένα ακέραιο. Οι δύο αριθμοί να εισάγονται από το πληκτρολόγιο.
Άσκηση 5 Να γραφεί πρόγραμμα που εμφανίζει τον προηγούμενο και τον επόμενο ακέραιο αριθμό ενός πραγματικού που εισάγεται από το πληκτρολόγιο.
Άσκηση 6 Να γραφεί πρόγραμμα που εμφανίζει στην οθόνη το παρακάτω αποτέλεσμα αφού εκχωρήσει πρώτα τους αριθμούς σε ακέραιες μεταβλητές.
Σύνοψη - printf scanf 48 Τύπος δεδομένων printf scanf float %f %f double %f ή %e %lf int %d %d char %c %c
Τέλος Ενότητας