Τμήμα Ηλεκτρονικών Μηχανικών Τ.Ε.Ι. Κρήτης Προγραμματισμός Η/Υ (ΤΛ2007 ) Δρ. Μηχ. Νικόλαος Πετράκης (npet@chania.teicrete.gr) Ιστοσελίδα Μαθήματος: https://eclass.chania.teicrete.gr/ Εξάμηνο: Εαρινό 2014-15
Μέτρηση λέξεων αρχείου κειμένου #include <stdio.h> // Μέτρηση λέξεων, γραμμών και #define OUT 0 // χαρακτήρων της πρότυπης εισόδου #define IN 1 // White spaces: \t \n main() { char ch; int nc=0,nw=0,nl=0,status=out; printf ("Πληκτρολόγησε ό,τι θέλεις... :\n"); while ((ch = getchar())!= EOF) { nc++; if (ch == \n ) nl++; if (ch == ch == \t ch == \n ) status=out; if (status==out) { nw++; status = IN; } } printf("υπήρχαν %d λέξεις, %d γραμμές και %d χαρακτήρες.\n",nw, nl, nc); } 2
Φωλιασμένα if (nested if) προηγούμενη_εντολή; if (λογική_έκφραση 1 ) εντολή 1 ; if (λογική_έκφραση 2 ) εντολή 2 ; if (λογική_έκφραση 3 ) εντολή 3 ;... if (λογική_έκφραση N ) εντολή N ; εναλλακτική_εντολή; προαιρετικό επόμενη_εντολή; 3
Η «μετέωρη» εντολή συνθήκης if Θα δούμε παρακάτω ένα κοινό λάθος στον προγραμματισμό της εντολής συνθήκης if-then-. Αρχικά, ας θεωρήσουμε μια σωστή δομή εντολής if, η οποία είναι σύνθετη (καθένα από τα if/ blocks της εντολής περιέχει με τη σειρά του μια άλλη εντολή if): if (λογική_έκφραση A ) if (λογική_έκφραση B ) εντολή 1 ; εντολή 2 ; if (λογική_έκφραση C ) εντολή 3 ; εντολή 4 ; 4
Ερμηνεία με διάγραμμα ροής True Α Συνθήκη False if (λογική_έκφραση A ) if (λογική_έκφραση B ) εντολή 1 ; εντολή2 ; if (λογική_έκφρασηc ) εντολή 3 ; εντολή4 ; True Β False True C False E1 E2 E3 E4 5
Εσφαλμένη παραλλαγή του προγράμματος Ας υποθέσουμε τώρα ότι δεν χρειαζόμαστε την εντολή 2. Τότε το διάγραμμα ροής θα γίνει: True Α False Δεν ξέρουμε αν αντιστοιχεί στο πρώτο ή στο δεύτερο if if (λογική_έκφραση A ) if (λογική_έκφραση B ) εντολή 1 ; if (λογική_έκφρασηc ) εντολή 3 ; εντολή4 ; Συνθήκη True Β False True C False E1 E3 E4 6
Σωστή παραλλαγή του προγράμματος Αν η Α αληθής και Β ψευδής τότε τερματίζει το πρόγραμμα E1 True Β False True Α Συνθήκη False Άγκιστρα E3 True C if (λογική_έκφραση A ) { if (λογική_έκφρασηb ) εντολή 1 ; } if (λογική_έκφρασηc ) εντολή 3 ; εντολή4 ; False E4 Καλή πρακτική: Χρήση άγκιστρων {} στις εντολές if ακόμη κι αν δεν απαιτούνται (δηλ. όταν ένα block if ή περιέχει μόνο μία εντολή) 7
Παρατηρήσεις Πρέπει να προσέχουμε διότι ο μεταφραστής δεν καταλαβαίνει τη στοίχιση του προγράμματος. Κατά τη μεταγλώττιση ο μεταφραστής αντιστοιχεί το με το τελευταίο «ανοικτό» if. Οπότε εάν γράψουμε: if (λογική_έκφραση A) if (λογική_έκφραση B) εντολή1; if (λογική_έκφραση C) εντολή3; εντολή4; True E1 Β True False E3 True C E4 Α Συνθήκη False False 8
Πολλαπλές εντολές συνθήκης Μία συχνή παραλλαγή είναι η πολλαπλή εντολή συνθήκης που σχηματικά παρουσιάζεται ως εξής:? Συνθήκη-1 Συνθήκη-2 Συνθήκη-3 Συνθήκη-4 Υπόλοιπες περιπτώσεις E1 E2 E3 E4 E5 9
Στη C οι πολλαπλές εντολές συνθήκης προγραμματίζονται με το παρακάτω ιδίωμα: if (λογική_έκφρασηα) εντολή1; if (λογική_έκφρασηβ) /* Είναι η συνθήκη-2 */ εντολή2; if (λογική_έκφρασηc) /* Είναι η συνθήκη-3 */ εντολή3; if (λογική_έκφρασηd) /* Είναι η συνθήκη-4 */ εντολή4; εντολή5; /* Είναι η συνθήκη-1 της προηγ. παραγράφου*/ 10
To παραπάνω ιδίωμα συνήθως γράφεται σαν: if (λογική_έκφρασηα)/*είναι η συνθήκη-1 της προηγ. παραγράφου*/ εντολή1; if (λογική_έκφρασηβ) /* Είναι η συνθήκη-2 */ εντολή2; if (λογική_έκφρασηc) /* Είναι η συνθήκη-3 */ εντολή3; if (λογική_έκφρασηd) /* Είναι η συνθήκη-4 */ εντολή4; εντολή5; 11
Εντολή πολλαπλής διακλάδωσης Εάν οι λογικές εκφράσεις στις συνθήκες είναι της μορφής a == 2, a==5, a==17 (δηλαδή η μεταβλητή που εξετάζεται στη συνθήκη είναι διακριτού τύπου (integer ή character), τότε υπάρχει και μία άλλη εντολή πολλαπλής διακλάδωσης. Ας θεωρήσουμε το παρακάτω πρόγραμμα: if (a == 2) statement1; if (a == 0 a == 3) statement2; if (a == 6) statement3; if (a == 8 a == 9) statement4; stattement5; switch (a) { case 2: statement1; break; case 0: case 3: statement2; break; case 6: statement3; break; case 8: case 9: statement4; break; default: statement5; break; ΠΡΟΣΟΧΗ: να μην παραλείπονται οι εντολές break! 12 }
Παράδειγμα # include <stdio.h> main() { int month, day, year; printf( Enter date (mm/dd/yyyy): ); scanf( %d/%d/%d, &month, &day, &year); printf ( %d, day); switch (day) { case 1: case 21: case 31: printf( st ); break; case 2: case 22: printf( nd ); break; case 3: case 23: printf( rd ); break; default: printf( th ); break; } } printf ( day of ); switch (month) { case 1: printf( January ); break; case 2: printf( February ); break; case 3: printf( March ); break; case 4: printf( April ); break; case 5: printf( May ); break; case 6: printf( June ); break; case 7: printf( July ); break; case 8: printf( August ); break; case 9: printf( September ); break; case 10: printf( October ); break; case 11: printf( November ); break; case 12: printf( December ); break; } printf (, %d..\n, year); return (0); 13
π.χ. αν δώσουμε την σημερινή ημερομηνία Enter date (mm/dd/yyyy): 3/26/2015 26th day of March, 2015.. Press any key to continue... ενώ για την πρωταπριλιά Enter date (mm/dd/yyyy): 4/1/2015 1st day of April, 2015.. Press any key to continue... 14
Εντολή επανάληψης do-while do { αρχικοποίηση μετρητή μεταβολή μετρητή επαναλαμβανόμενες_εντολές; } while (παράσταση ή συνθήκη); έλεγχος συνθήκης Σημείωση: Πρώτα εκτελώ μετά ελέγχω, άρα οι επαναλαμβανόμενες_εντολές θα εκτελεστούν τουλάχιστον μία φορά, ακόμα κι αν η συνθήκη είναι εξ αρχής ψευδής. 15
Παράδειγμα με do-while /* Υπολογισμός του αθροίσματος των τετραγώνων πραγματικών αριθμών μέχρι να δοθεί η τιμή -99.0 */ main() { double x=0.0, sum=0.0; int i=0; do { sum += x*x; ++i; printf( Δώστε τον %dο πραγματικό αριθμό :, i); scanf( %f,&x); }while (x!= -99.0); } printf( Το άθροισμα των τετραγώνων των αριθμών \ που δώσατε ισούται με %.3f \n\n, sum); 16
Xρήση αριθμημένων διατάξεων (πινάκων) Μία διάταξη (πίνακας) είναι μία συλλογή θέσεων αποθήκευσης δεδομένων, που έχουν τον ίδιο τύπο δεδομένων και το ίδιο όνομα. Κάθε θέση αποθήκευσης είναι ένα στοιχείο της διάταξης. 17
Μονοδιάστατες διατάξεις Μία μονοδιάστατη διάταξη έχει ένα όνομα και ένα δείκτη (αριθμός) που έπεται του ονόματος. float my_array [12]; H διάταξη με όνομα my_array έχει 12 στοιχεία τύπου float. Τα στοιχεία της διάταξης αρχίζουν από το 0 έως το 11. Τα στοιχεία της διάταξης αποθηκεύονται σε διαδοχικές θέσεις της μνήμης. 18
Χρήση στοιχείων διάταξης my_array [1] = 144.53; H πρόταση αποθηκεύει την τιμή 144,53 στο δεύτερο στοιχείο της διάταξης. my_array [10] = my_array [12]; my_array [1+2] = 57.5; το ίδιο με το: my_array [3] = 57.5; my_array[a[2]] = 67.20; // μόνο αν a είναι διάταξη ακέραιων 19
Xρήση διατάξεων Προσοχή στη χρήση δεικτών διατάξεων εκτός ορίων. Ο μεταγλωττιστής δε αναγνωρίζει απαραίτητα ότι είναι δείκτης εκτός ορίων με απρόβλεπτα αποτελέσματα. Αν θέλαμε να χρησιμοποιήσουμε διάταξη με δείκτη από 1 έως n, τότε θα μπορούσαμε να έχουμε διάταξη με ένα παραπάνω στοιχείο και να αγνοήσουμε το πρώτο με δείκτη 0. 20
Πολυδιάστατες διατάξεις Μία πολυδιάστατη διάταξη έχει περισσότερους από ένα δείκτες. Μία δισδιάστατη έχει 2 δείκτες. int checker [8][8]; // με 64 στοιχεία, από checker [0][0], // checker[0][1], έως checker[7][7]. Μία τρισδιάστατη διάταξη θα μπορούσε να θεωρηθεί ως ένας κύβος αλλά καλύτερα να αφεθούν στη φαντασία σας! 21
Παραδείγματα #define N 15 int array[n]; // Μπορούμε να αλλάξουμε το μέγεθος του πίνακα // στο #define χωρίς αλλαγές στο πρόγραμμα. 22
Απόδοση αρχικών τιμών int array[4] = {100, 200, 300, 400 }; To ίδιο αποτέλεσμα με: int array[] = {100, 200, 300, 400 }; int array[10] = {1,2,3 }; Mε απρόσμενα αποτελέσματα για λιγότερα στοιχεία, με λάθος μεταγλωττιστή για περισσότερα. 23
Απόδοση αρχικών τιμών Πολυδιάστατων διατάξεων: int array [4][3] = {1,2,3,4,5,6,7,8,9,10,11,12}; // Αρχικοποιεί τα στοιχεία ως εξής: // array[0][0] = 1, array[0][1] = 2, array[0][2] = 3, // array[1][0] = 4, array[1][1] = 5, array[1][2] = 6, // array[2][0] = 7, array[1][1] = 8, array[1][2] = 9, // array[3][0] =10, array[3][1]=11, array[3][2]=12. Ή ακόμα καλύτερα: int array [4][3] = { { 1,2,3}, {4,5,6}, {7,8,9}, {10,11,12} }; 24
Αποθήκευση Μία διάταξη 500 στοιχείων τύπου float απαιτεί 500 * 4 bytes 25
Οι συναρτήσεις srand() και rand() Ορίζονται στο stdlib.h με πρωτότυπο: int rand (void); // επιστρέφει ακέραιο μεταξύ 0 και // 32767 (RAND_MAX) void srand (unsigned int seed); // αρχικοποίηση γεννήτριας 26
Η συνάρτηση time () Ορίζεται στο time.h και την χρησιμοποιούμε για να αρχικοποιήσουμε την γεννήτρια σε μια τυχαία τιμή με βάση τον χρόνο του μηχανήματος ως εξής: srand ((unsigned) time (NULL)); 27
Ασκήσεις 1) Να γίνει πρόγραμμα, σε γλώσσα C, το οποίο να γεμίζει έναν πίνακα 15 στοιχείων με ψευδοτυχαίες ακέραιες τιμές από το κλειστό διάστημα [0, 100] και να τον εμφανίζει στην οθόνη σε μία γραμμή. 2) Να γίνει πρόγραμμα το οποίο να γεμίζει έναν πίνακα 12 στοιχείων με ψευδοτυχαίες ακέραιες τιμές από το κλειστό διάστημα [-10, +150] και να τον εμφανίζει στην οθόνη σε μία στήλη (δηλαδή το ένα στοιχείο κάτω από άλλο). 28