Ανάπτυξη Μεγάλων Εφαρµογών στη Γλώσσα C (2)

Μέγεθος: px
Εμφάνιση ξεκινά από τη σελίδα:

Download "Ανάπτυξη Μεγάλων Εφαρµογών στη Γλώσσα C (2)"

Transcript

1 Ανάπτυξη Μεγάλων Εφαρµογών στη Γλώσσα C (2) Στην ενότητα αυτή θα µελετηθούν τα εξής επιµέρους θέµατα: Οργάνωση Προγράµµατος Header Files Μετάφραση και σύνδεση αρχείων προγράµµατος ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1-1

2 Υλοποίηση µιας απλής αριθµοµηχανής Ζητείται η υλοποίηση ενός προγράµµατος που να υπολογίζει αριθµητικές εκφράσεις αντίστροφου πολωνικού συµβολισµού. Σύµφωνα µε αυτή, µια ενθεµατική αριθµητική έκφραση όπως η (3+6)*(8-6) παρουσιάζεται µε την παρακάτω µορφή * Είναι προφανές ότι σε αυτή τη µορφή δεν απαιτείται η χρήση των παρενθέσεων. Για τον υπολογισµό τέτοιων εκφράσεων µπορεί να χρησιµοποιηθεί η έννοια της στοίβας (stack): µιας λίστας που συνοδεύεται από τις διαδικασίες push, για εισαγωγή στοιχείου στο τέλος της λίστας, και pop, για εξαγωγή του τελευταίου στοιχείου της λίστας. ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1-2

3 Παράδειγµα Εκτέλεσης Έστω η παράσταση * -. ( Η σε ενθεµατική µορφή: 60 - (5+3)*(2+4) ) * * * * * - * - - ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1-3

4 Υλοποίηση αριθµοµηχανής (συν.) Η δοµή του προγράµµατος θα έχει τη µορφή της παρακάτω ανακύκλωσης: While (next operator or operand is not EOF) if (number) push it else if (operator) pop operands do operation push result else if (newline) pop and print top of stack else error Οι λειτουργίες push και pop µπορουν να υλοποιηθούν ως ξεχωριστές συναρτήσεις. Επίσης, πρέπει να γίνει αντιληπτό ότι το main δεν χρειάζεται να έχει πρόσβαση στις µεταβλητές που υλοποιούν τη στοίβα, απλά πρέπει να καλεί τις συναρτήσεις push και pop. ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1-4

5 Υλοποίηση αριθµοµηχανής (συν.) Θα χρησιµοποιήσουµε τις εξής συναρτήσεις: int getop(char s[], ) Η συνάρτηση αυτή θα διαβάζει τον επόµενο τελεστή ή τελεστέο της αριθµητικής έκφρασης. Αγνοεί οποιαδήποτε κενά και σταµατά όταν φτάσει στο τέλος της έκφρασης. Αν ο επόµενος αριθµός δεν είναι δεκαδικό στοιχείο, τότε τον επιστρέφει, διαφορετικά φυλάει στον πίνακα sµια σειρά χαρακτήρων (που πιθανόν να περιέχει και υποδιαστολή) και επιστρέφει τη τιµή ΝUMBER. void push(double, ) Η συνάρτηση αυτή εισάγει ένα double µέσα στη στοίβα. double pop ( ) H συνάρτηση αυτή διαβάζει και επιστρέφει το επόµενο στοιχείο της στοίβας. int main(void) Η συνάρτηση αυτή θα υλοποιεί µία ανακύκλωση στην οποία θα υπάρχει ένα µεγάλο switch πάνω στον τύπο του τελεστή ή του τελεστέου που διαβάζεται από την είσοδο. ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1-5

6 Υλοποίηση αριθµοµηχανής (συν.) Μια πιθανή δοµή του προτεινόµενου προγράµµατος είναι η παρακάτω: #includes #defines Function prototypes for main int main(void) { } External variables for push and pop void push(double f) { } double pop(void) { } int getop(char s[]) { } ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1-6

7 Υλοποίηση αριθµοµηχανής (συν.) #include <stdio.h> #include <stdlib.h> /* for atof() */ #define MAXOP 100 /* max size of operand or operator */ #define NUMBER 0 /* signal that a number was found */ int getop(char []); void push(double); double pop(void); int main(void) { int type; double op2; char s[maxop]; while ( (type = getop(s))!= EOF) { switch (type) { case NUMBER: push(atof(s)); break; case + : push( pop() + pop() ); break; ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1-7

8 Υλοποίηση αριθµοµηχανής (συν.) case * : push( pop() * pop() ); break; case - : op2 = pop(); push( pop() op2 ); break; case / : op2 = pop(); if (op2!=0.0) push(pop()/op2); else printf( error: zero divisor\n ); break; case \n : printf( result=%f, pop()); break; default: printf ( error: Unknown command\n ); break; } } return 0; } ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1-8

9 Υλοποίηση αριθµοµηχανής (συν.) /* stack implementation */ #define MAXVAL 100 /* max depth of stack */ int sp = 0; /* next free stack position */ double val[maxval]; /* value stack */ /* push: push f onto value stack */ void push(double f) { if (sp < MAXVAL) val[sp++] = f; else printf( error: stack full, can t push %f\n, f); } ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1-9

10 Υλοποίηση αριθµοµηχανής (συν.) /* pop: pop and return top value from stack */ Double pop(void) { if (sp>0) return val[--sp]; else { printf( error: stack empty\n ); return 0.0; } } Σύµφωνα µε την υλοποίηση, η στοίβα (val[]) και ο δείκτης στην κορυφή της στοίβας (sp) δεν µπορούν να προσπελαστούν από την main() αλλά µόνο από τις συναρτήσεις push() και pop(). Γι αυτό και δηλώθηκαν ως εξωτερικές µεταβλητές αλλά τοποθετήθηκαν κάτω από τον ορισµό της main(). ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1-10

11 Οργάνωση Προγράµµατος Ψάχνοντας µια καλύτερη οργάνωση του παραπάνω προγράµµατος χρησιµοποιούµε τη δυνατότητα κατάτµησης ενός προγράµµατος σε περισσότερα από ένα αρχεία. (Σηµείωση: η δυνατότητα αυτή χρησιµοποιείται κυρίως σε µεγάλα προγράµµατα). Μία καλύτερη λύση: 1. Η συνάρτηση main() να τοποθετηθεί σε ένα αρχείο το οποίο να ονοµαστεί main.c 2. Οι συναρτήσεις που υλοποιούν τη στοίβα να τοποθετηθούν στο αρχείο stack.c 3. Άλλες συναρτήσεις που επεξεργάζονται την είσοδο και βρίσκουν τους τελεστές και τους τελεστέους να τοποθετηθούν σε ένα τρίτο αρχείο, το getop.c. ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1-11

12 Οργάνωση Προγράµµατος (συν.) main.c stack.c getop.c #include <stdio.h> #include <stdio.h> #include <stdio.h> #include <stdlib.h> #define MAXVAL 100 #include <ctype.h> #define MAXOP 100 #define NUMBER 0 #define NUMBER 0 void push(double); int sp = 0; double pop(void); double val[maxval]; int getop(void) { int main(void) { void push(double) { } } } double pop(void) { } ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1-12

13 Header Files Ένα ακόµα θέµα που µας απασχολεί καθώς µοιράζουµε ένα πρόγραµµα σε περισσότερα από ένα αρχεία είναι οι κοινοί ορισµοί και οι δηλώσεις µεταξύ των αρχείων αυτών. Προσπαθούµε λοιπόν ως τελευταίο βήµα της παραπάνω διαδικασίας οργάνωσης, να µαζέψουµε κεντρικά σε ένα αρχείο όλες τις δηλώσεις το οποίο ονοµάζεται header file. Στην περίπτωσή µας κατασκευάζουµε το αρχείο calc.h το οποίο έχει το εξής περιεχόµενο: calc.h #define NUMBER 0 void push(double); double pop (void); int getop(char []); Το προτεινόµενο πρόγραµµα γίνεται συνεπώς ως εξής: ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1-13

14 Οργάνωση Προγράµµατος (συν.) main.c stack.c getop.c #include <stdio.h> #include <stdio.h> #include <stdio.h> #include <stdlib.h> #include calc.h #include <ctype.h> #include calc.h #define MAXVAL 100 #include calc.h #define MAXOP 100 int sp = 0; double val[maxval]; int getop(void) { int main(void) { void push(double) { } } } double pop(void) { } ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1-14

15 Οργάνωση Προγράµµατος (συν.) Πιθανά Προβλήµατα: τα ονόµατα των µεταβλητών val και sp που χρησιµοποιούνται για την υλοποίηση της στοίβας είναι για αποκλειστική χρήση των συναρτήσεων push() και pop(). Τι γίνεται αν οριστούν ξανά (κατά λάθος) σε ένα άλλο αρχείο; Θα έχουµε δύο εξωτερικές µεταβλητές µε το ίδιο όνοµα!!! Λύση: Ορίζοντας τις µεταβλητές val και sp στο αρχείο stack.c ως static περιορίζουµε την εµβέλεια των µεταβλητών αυτών στο αρχείο το οποίο ορίζονται. Έτσι, αποφεύγεται η σύγκρουση σε δηλώσεις συνώνυµων µεταβλητών σε άλλα αρχεια. Στο αρχείο stack.c έχουµε συνεπώς τις δηλώσεις: static int sp = 0; static double val[maxval]; ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1-15

16 Μετάφραση Πολλαπλών Αρχείων Στο παραπάνω παράδειγµα µπορούµε να χρησιµοποιήσουµε τις εξής εντολές: 1. cc c main.c ηµιουργία του main.o 2. cc c stack.c ηµιουργία του stack.o 3. cc c getop.c ηµιουργία του getop.o 4. cc o calculator main.o stack.o getop.o Σύνδεση των object files και η δηµιουργία του εκτελέσιµου προγράµµατος calculator Ή διαφορετικά σε ένα βήµα: cc o calculator main.c stack.c getop.c ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1-16

17 Εργασία 1. Βρείτε τη χρησιµότητα της παραπάνω αντιµετώπισης στην οργάνωση µεγάλων προγραµµάτων. 2. Έχοντας δηµιουργήσει τα παραπάνω αρχεία που υλοποιούν την αριθµοµηχανή, υλοποιήστε ένα πρόγραµµα το οποίο παίρνει σαν είσοδο µια σειρά πραγµατικών αριθµών και τυπώνει αυτή τη σειρά αντίστροφα. (Χρησιµοποιήστε µία στοίβα για την υλοποίηση του προβλήµατος...). Τι παρατηρήσατε κατά την υλοποίηση; 3. Ποια η διαφορά στη χρήση της λέξης κλειδί static όταν αυτή χρησιµοποιείται σε εξωτερικές µεταβλητές και όταν χρησιµοποιείται σε αυτόµατες µεταβλητές (στο σώµα δηλαδή των συναρτήσεων). ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1-17