Τεχνολογικό Εκπαιδευτικό Ίδρυμα Κρήτης Σχολή Εφαρμοσμένων Επιστημών Τμήμα Ηλεκτρονικών Μηχανικών Τομέας Αυτοματισμού και Πληροφορικής Δομημένος Προγραμματισμός (ΤΛ1006) Δρ. Μηχ. Νικόλαος Πετράκης, Καθηγητής Εφαρμογών (npet@chania.teicrete.gr) Έκτη (6 η ) τρίωρη διάλεξη. Ιστοσελίδα Μαθήματος: https://eclass.chania.teicrete.gr/courses/el106 Εξάμηνο: Χειμερινό 2017-18
Πολλαπλές εντολές συνθήκης Μία συχνή παραλλαγή της απλής εντολής συνθήκης είναι η πολλαπλή εντολή συνθήκης που σχηματικά παρουσιάζεται ως εξής:? Συνθήκη-1 Συνθήκη-2 Συνθήκη-3 Συνθήκη-4 Υπόλοιπες περιπτώσεις E1 E2 E3 E4 E5 Ανάλογα με το ποια συνθήκη είναι αληθής εκτελείται και η κατάλληλη ομάδα εντολών. Π.χ. αν είναι αληθής η Συνθήκη-1 τότε θα εκτελεστεί η ομάδα Ε1, ενώ αν είναι αληθής η Συνθήκη-2 τότε θα εκτελεστεί η ομάδα Ε2. 2
Στη C οι πολλαπλές εντολές συνθήκης προγραμματίζονται με το παρακάτω ιδίωμα: if (λογική_έκφρασηα) εντολή1; else if (λογική_έκφρασηβ) /* Είναι η συνθήκη-2 */ εντολή2; else if (λογική_έκφρασηc) /* Είναι η συνθήκη-3 */ εντολή3; else if (λογική_έκφρασηd) /* Είναι η συνθήκη-4 */ εντολή4; else /* Υπόλοιπες περιπτώσεις */ εντολή5; /* Είναι η συνθήκη-1 της προηγ. παραγράφου*/ 3
To παραπάνω ιδίωμα συνήθως γράφεται σαν: if (λογική_έκφρασηα)/*είναι η συνθήκη-1 της προηγ. παραγράφου*/ εντολή1; else if (λογική_έκφρασηβ) /* Είναι η συνθήκη-2 */ εντολή2; else if (λογική_έκφρασηc) /* Είναι η συνθήκη-3 */ εντολή3; else if (λογική_έκφρασηd) /* Είναι η συνθήκη-4 */ εντολή4; else /* Υπόλοιπες περιπτώσεις */ εντολή5; και είναι γνωστό ως «ενφωλευμένα αν» ή φωλιασμένα if. 4
Φωλιασμένα if (Nested - IFs) προηγούμενη_εντολή; if (λογική_έκφραση 1 ) εντολή 1 ; else if (λογική_έκφραση 2 ) εντολή 2 ; else if (λογική_έκφραση 3 ) εντολή 3 ;... else if (λογική_έκφραση N ) εντολή N ; else εναλλακτική_εντολή; προαιρετικό επόμενη_εντολή; 5
Η «μετέωρη» εντολή συνθήκης if Θα δούμε παρακάτω ένα κοινό λάθος στον προγραμματισμό της εντολής συνθήκης if-then-else. Αρχικά, ας θεωρήσουμε μια σωστή δομή εντολής if, η οποία είναι σύνθετη (καθένα από τα if/else blocks της εντολής περιέχει με τη σειρά του μια άλλη εντολή if): if (λογική_έκφραση A ) if (λογική_έκφραση B ) εντολή 1 ; else εντολή 2 ; else if (λογική_έκφραση C ) εντολή 3 ; else εντολή 4 ; 6
Ερμηνεία με διάγραμμα ροής if (λογική_έκφραση A ) if (λογική_έκφραση B ) εντολή 1 ; else εντολή2 ; True Α False else if (λογική_έκφρασηc ) εντολή 3 ; else εντολή4 ; Συνθήκη True Β False True C False E1 E2 E3 E4 7
Εσφαλμένη παραλλαγή του προγράμματος Ας υποθέσουμε τώρα ότι δεν χρειαζόμαστε την εντολή 2. Τότε το διάγραμμα ροής θα γίνει: True Α False Δεν ξέρουμε αν αντιστοιχεί στο πρώτο ή στο δεύτερο if if (λογική_έκφραση A ) if (λογική_έκφραση B ) εντολή 1 ; else if (λογική_έκφρασηc ) εντολή 3 ; else εντολή4 ; Συνθήκη True Β False True C False E1 E3 E4 8
Σωστή παραλλαγή του προγράμματος Αν η Α αληθής και Β ψευδής τότε τερματίζει το πρόγραμμα True Α False Άγκιστρα if (λογική_έκφραση A ) { if (λογική_έκφρασηb ) εντολή 1 ; } else if (λογική_έκφρασηc ) εντολή 3 ; else εντολή4 ; Συνθήκη E1 True Β False E3 True C False E4 Καλή πρακτική: Χρήση άγκιστρων {} στις εντολές if ακόμη κι αν δεν απαιτούνται (δηλ. όταν ένα block if ή else περιέχει μόνο μία εντολή) 9
Παρατηρήσεις Πρέπει να προσέχουμε διότι ο μεταφραστής δεν καταλαβαίνει τη στοίχιση του προγράμματος. Κατά τη μεταγλώττιση ο μεταφραστής αντιστοιχεί το else με το τελευταίο «ανοικτό» if. Οπότε το προηγούμενο λάθος θα True False Α έδινε ισοδύναμο κώδικα σαν αυτόν που ακολουθεί: Συνθήκη if (λογική_έκφραση A) if (λογική_έκφραση B) εντολή1; else if (λογική_έκφραση C) εντολή3; else εντολή4; True E1 Β True False E3 C E4 False 10
Εντολή πολλαπλής διακλάδωσης Εάν οι λογικές εκφράσεις στις συνθήκες είναι της μορφής a == 2, a==5, a==17 (δηλαδή η μεταβλητή που εξετάζεται στη συνθήκη είναι διακριτού τύπου (integer ή character), τότε υπάρχει και μία άλλη εντολή πολλαπλής διακλάδωσης. Ας θεωρήσουμε το παρακάτω πρόγραμμα: if (a == 2) statement1; else if (a == 0 a == 3) statement2; else if (a == 6) statement3; else if (a == 8 a == 9) statement4; else statement5; ΠΡΟΣΟΧΗ: να μην παραλείπονται οι εντολές break! 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; } 11
Παράδειγμα # 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); 12
π.χ. αν δώσουμε την σημερινή ημερομηνία Enter date (mm/dd/yyyy): 11/28/2017 28th day of November, 2017.. Press any key to continue... ενώ για την επόμενη πρωταπριλιά Enter date (mm/dd/yyyy): 4/1/2018 1st day of April, 2018.. Press any key to continue... 13
Εντολή επανάληψης do-while do { αρχικοποίηση μετρητή επαναλαμβανόμενες_εντολές; } while (παράσταση ή συνθήκη); μεταβολή μετρητή έλεγχος συνθήκης Σημείωση: Πρώτα εκτελώ μετά ελέγχω, άρα οι επαναλαμβανόμενες_εντολές θα εκτελεστούν τουλάχιστον μία φορά, ακόμα κι αν η συνθήκη είναι εξ αρχής ψευδής. 14
Παράδειγμα με 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); 15
Αριθμημένες διατάξεις (πίνακες) Μία διάταξη (πίνακας) είναι μία συλλογή θέσεων αποθήκευσης δεδομένων, που έχουν τον ίδιο τύπο δεδομένων και το ίδιο όνομα. Κάθε θέση αποθήκευσης είναι ένα στοιχείο της διάταξης. Όλα τα στοιχεία του πίνακα καταλαμβάνουν συνεχόμενες-διαδοχικές θέσεις στην μνήμη του υπολογιστή. 16
Μονοδιάστατες διατάξεις Μία μονοδιάστατη διάταξη έχει ένα όνομα και ένα αριθμοδείκτη που έπεται του ονόματος. float my_array [12]; H διάταξη με όνομα my_array έχει 12 στοιχεία τύπου float το καθένα. Τα στοιχεία της διάταξης αρχίζουν από την θέση με αριθμοδείκτη 0 και φθάνουν έως το 11. Τα στοιχεία της διάταξης αποθηκεύονται σε διαδοχικές θέσεις της μνήμης. 17
Χρήση στοιχείων διάταξης my_array [1] = 144.53; H πρόταση αποθηκεύει την τιμή 144,53 στο δεύτερο στοιχείο της διάταξης. my_array [1+2] = 57.5; Είναι ισοδύναμο με το: my_array [3] = 57.5; my_array [10] = my_array [12]; Αποθηκεύει στο ενδέκατο στοιχείο της διάταξης την τιμή του δέκατου-τρίτου στοιχείου!!. my_array[a[2]] = 67.20; Μπορεί να γίνει, μόνο, αν η μεταβλητή a είναι διάταξη ακέραιων 18
Xρήση διατάξεων Προσοχή στη χρήση αριθμοδεικτών διατάξεων οι οποίοι είναι εκτός ορίων. Ο μεταγλωττιστής δε κάνει έλεγχο ορίων, οπότε αν ο προγραμματιστής δεν είναι προσεκτικός θα αντιμετωπίσει απρόβλεπτα αποτελέσματα. Όλες οι διατάξεις στην C αρχίζουν με αριθμοδείκτη 0 Αν θέλουμε να χρησιμοποιήσουμε διάταξη με αριθμοδείκτη από το 1 έως το n, τότε θα πρέπει να ορίσουμε την διάταξη με ένα παραπάνω στοιχείο και να αγνοήσουμε το πρώτο (αυτό με αριθμοδείκτη 0). 19
Πολυδιάστατες διατάξεις Μία πολυδιάστατη διάταξη έχει περισσότερους από ένα δείκτες. Μία διδιάστατη έχει 2 δείκτες. int checker [8][8]; // με 64 στοιχεία, από checker [0][0], // checker[0][1], έως checker[7][7]. Μία τριδιάστατη διάταξη θα μπορούσε να θεωρηθεί ως ένας κύβος αλλά καλύτερα να αφεθούν στη φαντασία σας! 20
Παραδείγματα #define M 20 #define N 15 int array[n], p[m][n], p3[n][n][n]; // Μπορούμε να αλλάξουμε το μέγεθος του πίνακα // στο #define χωρίς αλλαγές στο πρόγραμμα. float pinakas[500]; // Η αποθήκευση της προηγούμενης διάταξης η // οποία έχει 500 στοιχεία τύπου float το καθένα // απαιτεί χωρητικότητα 500 4 bytes = 2KBytes. 21
Απόδοση αρχικών τιμών int array[4] = {100, 200, 300, 400}; To ίδιο αποτέλεσμα με: int array[] = {100, 200, 300, 400}; Ενώ, αν το μέγεθος του πίνακα είναι διαφορετικό από το πλήθος των στοιχείων που δίδονται (αρχικών τιμών), όπως, π.χ.: int array[10] = {1,2,3}; θα έχουμε: είτε απρόσμενα αποτελέσματα, για λιγότερα στοιχεία, είτε λάθος μεταγλωττιστή, για περισσότερα. 22
Απόδοση αρχικών τιμών Πολυδιάστατων διατάξεων: 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} }; 23
Οι συναρτήσεις srand() και rand() Ορίζονται στο stdlib.h και επικουρούν στην χρήση της γεννήτριας ψευδοτυχαίων αριθμών με πρωτότυπο: int rand (void); // επιστρέφει ακέραιο μεταξύ 0 και 32767 (RAND_MAX) void srand (unsigned int seed); // αρχικοποίηση της γεννήτριας 24
Η συνάρτηση time () Ορίζεται στο time.h (οπότε συνήθως πρέπει να συμπεριλάβουμε στην αρχή του κώδικά μας την γραμμή #include <time.h> ) και την χρησιμοποιούμε για να αρχικοποιήσουμε την γεννήτρια σε μια τυχαία τιμή με βάση τον χρόνο του μηχανήματος ως εξής: srand ((unsigned) time (NULL)); 25
Γεννήτρια ψευδοτυχαίων αριθμών από 0 έως 32767 x = rand(); 41 18467 6334 26500 19169 15724 11478... Αν θέλαμε ψυδοτυχαίους αριθμούς από 0 έως 100 θα γράφαμε: x = rand()%101; και θα λαμβάναμε: 41 85 72 38 80 69 65... Αν θέλαμε ψυδοτυχαίους αριθμούς από 40 έως 60 θα γράφαμε: x = 40 + rand()%21; και βέβαια δεν πρέπει να παραλείψουμε την: srand((unsigned)time(null)); 26
Παράδειγμα γεμίσματος πίνακα #include <stdio.h> #include <stdlib.h> #include <greek.h> #define N 15 #define K 50 #define L 80 int main(int argc, char *argv[]) { int p[n],i; SetGreek(); srand((unsigned)time(null)); for (i=0; i<n; i++) p[i]= K + rand()%(l-k+1); printf("\nο πίνακας είναι:\n"); for (i=0; i<n; i++) printf("%3d", p[i]); printf("\n"); system("pause"); return 0; } Να γίνει ένα πρόγραμμα που να γεμίζει έναν πίνακα 15 ακεραίων με (ψευδο)τυχαίες τιμές από το 50 έως και το 80 η καθεμία. Κατόπιν να τον εμφανίζει στην οθόνη σε μία γραμμή. 27
Αποτελέσματα εκτέλεσης προηγούμενου προγράμματος O πίνακας είναι: 60 72 60 76 61 57 58 51 73 55 51 78 50 75 60 Πιέστε ένα πλήκτρο για συνέχεια... Χωρίς την χρήση της srand() O πίνακας είναι: 76 74 54 64 59 50 50 73 63 71 50 77 53 51 58 Πιέστε ένα πλήκτρο για συνέχεια... O πίνακας είναι: 55 56 57 61 68 52 75 76 76 58 64 53 53 54 71 Πιέστε ένα πλήκτρο για συνέχεια... Με την χρήση της srand() 28
Ασκήσεις 1) Να γίνει πρόγραμμα, σε γλώσσα C, το οποίο να γεμίζει έναν πίνακα 15 στοιχείων με ψευδοτυχαίες ακέραιες τιμές από το κλειστό διάστημα [0, 100] και να τον εμφανίζει στην οθόνη σε μία γραμμή. 2) Να γίνει πρόγραμμα το οποίο να γεμίζει έναν πίνακα 12 στοιχείων με ψευδοτυχαίες ακέραιες τιμές από το κλειστό διάστημα [-10, +150] και να τον εμφανίζει στην οθόνη σε μία στήλη (δηλαδή το ένα στοιχείο κάτω από άλλο). 29
Παράδειγμα δημιουργίας μενού επιλογής... do{ printf("\n ΜΕΝΟΥ ΕΠΙΛΟΓΗΣ"); printf("\n 1. ααα... "); printf("\n 2. βββ... "); printf("\n 3. γγγ... ");... printf("\n 0. ΕΞΟΔΟΣ "); printf("\n\n ΔΩΣΤΕ ΕΠΙΛΟΓΗ : "); scanf ("%d", &choice); }while(choice<0 choice>3); switch (choice) { case 1:... break; case 2:... break; case 3:... break; case 0: exit(1); }... break; 30
Οι εντολές break και continue Κάποιες φορές εξυπηρετεί να μπορούμε να βγούμε από ένα βρόχο χωρίς να εκτελέσουμε τον έλεγχο της αρχής ή του τέλους. Η εντολή break προσφέρει πρόωρη έξοδο από τις for, while και do-while ακριβώς όπως και στην switch. Προκαλεί δηλαδή άμεση έξοδο από τον πιο εσωτερικό βρόχο εντολής επανάληψης ή πολλαπλής διακλάδωσης switch. Η εντολή continue προκαλεί την έναρξη του επόμενου βρόχου for, while, ή do-while που την περιέχει. Στους while και do-while αυτό σημαίνει ότι εκτελείται αμέσως το τμήμα ελέγχου, ενώ στην for ο έλεγχος περνάει στο βήμα αύξησης. Η εντολή continue εφαρμόζεται μόνο σε βρόχους, και όχι στην switch. Η continue χρησιμοποιείται συχνά όταν το τμήμα του βρόχου που ακολουθεί είναι περίπλοκο, με αποτέλεσμα η αντιστροφή ενός ελέγχου και η δημιουργία ακόμα μιας εσοχής να βάζει το πρόγραμμα σε επαλληλίες με πολύ μεγάλο βάθος. Οι εντολές break και continue χρησιμοποιούνται σπάνια. 31
Η εντολή goto Η εντολή goto προκαλεί άμεση μετάβαση (άλμα) στην ετικέτα Χρησιμοποιείται για να προκαλέσει την έξοδο από μια βαθιά φωλιασμένη δομή, όπως από δυο ή περισσότερους βρόχους. Η εντολή break, που είδαμε λίγο πριν, δεν μπορεί να χρησιμοποιηθεί άμεσα, διότι προκαλεί την έξοδο μόνο από τον πιο εσωτερικό βρόχο. Η χρήση της goto δεν συστήνεται, παρά μόνο σε πολύ ειδικές περιπτώσεις. for (... ) for (... ) for (... ) {... if (disaster) goto error; }... error: /* ονομασία ετικέτας */... 32
O τελεστής κόμμα «,» Σε ορισμένες περιπτώσεις το κόμμα ενεργεί ως τελεστής παρά ως απλό διαχωριστικό. Το αποτέλεσμα είναι το εξής: Υπολογίζονται και οι δύο εκφράσεις με πρώτη την αριστερή έκφραση. Ολόκληρη η έκφραση εκτιμάται στην τιμή της δεξιάς έκφρασης. x = (a++, b++) H πρόταση αυτή εκχωρεί την τιμή της b στην x, κατόπιν αυξάνει την a κατά ένα και μετά αυξάνει την b κατά ένα. Τελεστής χαμηλής προτεραιότητας. Π.χ. Αντιστροφή στοιχείων πίνακα: int p[15], i, j, t; for(i=0,j=14; i<j ; i++, j--) { t = p[i]; p[i] = p[j]; p[j] = t; } 33
Εισαγωγή στις συναρτήσεις Στη C ο όρος «συνάρτηση» ορίζει μία ακολουθία εντολών που έχουν ομαδοποιηθεί και καταχωρηθεί μ ένα συμβολικό όνομα. Στη C κάθε συνάρτηση είναι ουσιαστικά ένα μικρό πρόγραμμα, με τις δικές του δηλώσεις μεταβλητών, και τις δικές του εντολές. Δηλαδή μια συνάρτηση είναι κατονομασμένη, ανεξάρτητη, εκτελεί συγκεκριμένη εργασία, μπορεί να λάβει παραμέτρους (ορίσματα) και μπορεί να επιστρέψει κάποιο αποτέλεσμα Η ιδέα είναι ότι ένας σύνθετος αλγόριθμος μπορεί να διασπασθεί σε μικρότερα κομμάτια τα οποία είναι ευκολότερο να κατανοηθούν, να υλοποιηθούν, και να συντηρηθούν (αναλυτική σχεδίαση αλγορίθμων top down). Κάθε τέτοιο κομμάτι μπορεί να υλοποιηθεί σαν μία συνάρτηση. 34
Αναλυτική (Κάθετη top down) μεθοδολογία επίλυσης προβλημάτων Σύνθετο Πρόβλημα Υπο- Πρόβλημα 1 Υπο- Πρόβλημα 2 Υπο- Πρόβλημα 3 Υπο- Πρόβλημα 1-1 Υπο- Πρόβλημα 1-2 Υπο- Πρόβλημα 2-1 Υπο- Πρόβλημα 3-1 Υπο- Πρόβλημα 3-2 35
Οργάνωση προγράμματος main Συνάρτηση-1 Συνάρτηση-2 Συνάρτηση-3 Συνάρτηση-1.1 Συνάρτηση-1.2 Συνάρτηση-2.1 Συνάρτηση-3.1 Συνάρτηση-3.2 36
Η έννοια του Δομημένου Προγραμματισμού Δομημένος Προγραμματισμός είναι όταν εκτελούμε μεμονωμένες εργασίες προγράμματος από αυτόνομα τμήματα κώδικα. Είναι ευκολότερο να γράψουμε ένα πρόγραμμα όταν είναι μοιρασμένο σε συναρτήσεις, ακόμα πιο εύκολο να εντοπίσουμε τα λάθη, αλλά και πιο βολικό στο να το εξελίξουμε περισσότερο. Επαναχρησιμοποιούμε συναρτήσεις. Χρησιμοποιώντας δομημένο προγραμματισμό, ο προγραμματιστής χρησιμοποιεί την «κάθετη προσέγγιση» (δενδρική μορφή υπο-προβλημάτων). Για αυτό πολλά προγράμματα της C, έχουν λίγες γραμμές κώδικα στη main(). 37
Συναρτήσεις και δομημένος προγραμματισμός Για να γράψουμε ένα δομημένο πρόγραμμα, χρειάζεται να κάνουμε πρώτα λίστα συγκεκριμένων εργασιών που πρέπει να εκτελεστούν. Ιεραρχική δομή προγράμματος, κάθετη προσέγγιση. Ως αποτέλεσμα, πολλά προγράμματα της C έχουν λίγο κώδικα στη main() που απλά οδηγεί την εκτέλεση του προγράμματος στις συναρτήσεις. Η C δεν βάζει περιορισμούς σε σχέση με το μήκος μίας συνάρτησης, αλλά συνήθως οι συναρτήσεις δεν υπερβαίνουν τις 25 γραμμές κώδικα. Και αυτό διότι στο δομημένο προγραμματισμό κάθε συνάρτηση εκτελεί μία σχετικά απλή εργασία. 38
Δομή Προγράμματος #include <stdio.h>. #define.. Δηλώσεις πρωτοτύπων Δηλώσεις μεταβλητών-α void main() { Δηλώσεις τοπικών μεταβλητών-β...... κλήση συνάρτηση-1(... );... κλήση συνάρτηση-2(... );... κλήση συνάρτηση-3(... );... } Τύπος_επιστροφής όνομα (τύπος όνομα_ορίσματος1,...) { Δηλώσεις τοπικών μεταβλητών-γ...... κλήση συνάρτηση-1.1(..)... κλήση συνάρτηση-1.2(...) } Τύπος συνάρτηση-1.1(τύπος παράμετρος,...) { Δηλώσεις τοπικών μεταβλητών-δ...... }...... Τύπος συνάρτηση-2(τύπος παράμετρος,...) { Δηλώσεις τοπικών μεταβλητών-ε...... } 39
Ροή Προγράμματος void main() { κλήση συνάρτηση-1 (...);... κλήση συνάρτηση-2(...);... κλήση συνάρτηση-3(...);... } τύπος συνάρτηση-1(...) {... κλήση συνάρτηση-1.1(..);... κλήση συνάρτηση-1.2(..);... } τύπος συνάρτηση-1.1(...) {...... } Μέσα σε μία συνάρτηση μπορούμε να καλέσουμε άλλη συνάρτηση Το μόνο πράγμα που δεν μπορούμε να κάνουμε μέσα σε μία συνάρτηση είναι να δηλώσουμε μία άλλη συνάρτηση. 40
Ορολογία σχετική με συναρτήσεις Δήλωση ή Πρωτότυπο συνάρτησης (function declaration) Ορισμός συνάρτησης (function definition) Επικεφαλίδα συνάρτησης (function header) Τυπικές παράμετροι συνάρτησης (formal parameters) Πραγματικά ορίσματα συνάρτησης (actual arguments) Σώμα συνάρτησης (function body) Κλήση συνάρτησης (function call) Διοχέτευση ορισμάτων (parameter passing) κατά αξία (by value) κατά αναφορά (by reference) Επιστροφή τιμών (return values) 41
Πρωτότυπο συνάρτησης Οι συναρτήσεις είναι και αυτές στοιχεία και κατασκευές της γλώσσας και σαν τέτοια πρέπει να δηλωθούν. Το πρόβλημα όμως είναι ότι σ ένα μεγάλο πρόγραμμα το οποίο αποτελείται από πολλά αρχεία μια συνάρτηση μπορεί να δηλωθεί ή ορισθεί σε οποιοδήποτε από αυτά. Το πρωτότυπο μίας συνάρτησης είναι μια δήλωση που παρέχει στον μεταγλωττιστή την πληροφορία ότι κάπου αργότερα στο πρόγραμμα η συνάρτηση θα ορισθεί. Το πρωτότυπο περιλαμβάνει το όνομα της συνάρτησης, τον τύπο του αποτελέσματος που επιστρέφει (αν επιστρέφει κάποιο αποτέλεσμα, διαφορετικά βάζουμε τύπο void), υποχρεωτικά τον τύπο και (προαιρετικά) το όνομα κάθε ορίσματος. Η σύνταξη του πρωτότυπου μιας συνάρτησης είναι: <τύπος> <όνομα_συνάρτησης>(τύπος 1 παράμ 1, τύπος κ παράμ κ ); Το πρωτότυπο τελειώνει πάντα με ένα ελληνικό ερωτηματικό (semicolon). 42
Πρωτότυπο συνάρτησης Το χρησιμοποιεί ο μεταγλωττιστής για να ελέγξει ότι διοχετεύεται ο σωστός αριθμός και τύπος ορισμάτων και ότι χρησιμοποιείται σωστά η τιμή επιστροφής. Ένα πρωτότυπο συνάρτησης δε χρειάζεται να αντιστοιχεί ακριβώς στην κεφαλίδα της συνάρτησης. Τα ονόματα παραμέτρων μπορούν να είναι διαφορετικά εφόσον είναι του ίδιου τύπου, έχουν το ίδιο πλήθος και ασφαλώς με την ίδια σειρά. Με το να είναι ίδια, ο πηγαίος σας κώδικας γίνεται κατανοητός. 43
Πρωτότυπο - σχηματικά #include <stdio.h>. #define.. Δηλώσεις πρωτοτύπων Δηλώσεις μεταβλητών-α void main() { Δηλώσεις τοπικών μεταβλητών-β...... κλήση συνάρτηση-1(..);... κλήση συνάρτηση-2(..);... κλήση συνάρτηση-3(..);... } Τύπος συνάρτηση-1(τύπος παράμετρος,...) { Δηλώσεις τοπικών μεταβλητών-γ...... κλήση συνάρτηση-1.1(..)... κλήση συνάρτηση-1.2(...) } Τύπος συνάρτηση-1.1(τύπος παράμετρος,...) { Δηλώσεις τοπικών μεταβλητών-δ...... }...... Τύπος συνάρτηση-2(τύπος παράμετρος,...) { Δηλώσεις τοπικών μεταβλητών-ε...... } 44
Ορισμός συνάρτησης Η κάθε συνάρτηση έχει ως σκοπό να υλοποιήσει και να εκτελέσει ένα συγκεκριμένο κομμάτι ενός αλγόριθμου. Συνεπώς ο προγραμματιστής θα πρέπει να γράψει τον κώδικα που αντιστοιχεί στην υλοποίηση αυτού του κομματιού. Η πρώτη γραμμή (κεφαλίδα) ενός ορισμού συνάρτησης θα πρέπει να είναι ίδια με του πρωτοτύπου της συνάρτησης χωρίς το ελληνικό ερωτηματικό στο τέλος. Αν και τα ονόματα των μεταβλητών είναι προαιρετικά στο πρωτότυπο, πρέπει υποχρεωτικά να περιλαμβάνονται στην κεφαλίδα συνάρτησης. Αυτό γίνεται με τον ορισμό της συνάρτησης που έχει τη μορφή <τύπος επιστροφής> <όνομα_συνάρτησης> (τύπος 1 παράμετρος 1,... τύπος κ παράμετρος κ ) { }... κώδικας συνάρτησης... Εάν ο τύπος επιστροφής της συνάρτησης είναι διαφορετικός του void, θα πρέπει να συμπεριλαμβάνεται μέσα στο σώμα της συνάρτησης μία πρόταση return η οποία επιστρέφει μία τιμή με τον προκαθορισμένο τύπο επιστροφής. 45
Κεφαλίδα συνάρτησης H πρώτη γραμμή του ορισμού κάθε συνάρτησης είναι η κεφαλίδα της. Αποτελείται από τον τύπο επιστροφής της συνάρτησης ο οποίος καθορίζει τον τύπο δεδομένων που επιστρέφει η συνάρτηση στο πρόγραμμα που την καλεί. Από το όνομα της συνάρτησης το οποίο πρέπει να ακολουθεί τους κανόνες ονομάτων των μεταβλητών της C. Πολλές συναρτήσεις χρησιμοποιούν ορίσματα που είναι τιμές οι οποίες διοχετεύονται στη συνάρτηση όταν καλείται. double function1 (int x, float y, char z) Ο τύπος επιστροφής μπορεί να είναι οποιοσδήποτε από τους τύπους δεδομένων της C: char, int, long, float, double. Κάποιες συναρτήσεις δεν δέχονται ορίσματα, ή δεν επιστρέφουν κάποια τιμή, πχ: void funct2 (int x, float y) ή void funct3 (void) 46
Τυπικές και πραγματικές παράμετροι (ορίσματα) Οι τυπικές παράμετροι της συνάρτησης είναι όλες οι παράμετροι που βρίσκονται στη κεφαλίδα της συνάρτησης (στο πρωτότυπο της συνάρτησης και στον ορισμό της συνάρτησης). Το πλήθος των παραμέτρων και ο τύπος κάθε παραμέτρου πρέπει να είναι ο ίδιος με το πρωτότυπο της συνάρτησης. Το ίδιο ισχύει για τον τύπο επιστροφής της συνάρτησης. Οι πραγματικές παράμετροι της συνάρτησης είναι οι τιμές των παραμέτρων για μια συγκεκριμένη κλήση της συνάρτησης, σε κάποιο σημείο του προγράμματος. Το πλήθος και ο τύπος των παραμέτρων/ορισμάτων πρέπει να είναι ο ίδιος με το πρωτότυπο και τον ορισμό της συνάρτησης. Το ίδιο ισχύει για τον τύπο επιστροφής της συνάρτησης στο σημείο κλήσης. 47
Παράδειγμα /* Να γίνει πρόγραμμα το οποίο να υπολογίζει το άθροισμα δύο ακέραιων αριθμών που δίδονται από το πληκτρολόγιο. Ο Υπολογισμός να γίνει σε ξεχωριστή συνάρτηση. */ #include <stdio.h> int sum(int, int); void main() { int i, j, k; printf("enter two numbers:"); scanf("%d%d", &i, &j); Τυπικά Ορίσματα (number1, number2) Πραγματικά Ορίσματα (i, j) k = sum( i, j ); } printf("the sum of %d, %d is: %d", i, j, k); int sum(int number1, int number2) { int m; m = number1 + number2; return m; } 48