ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ Η/Υ Ακαδημαϊκό έτος 2001-2002 ΤΕΤΡΑΔΙΟ ΕΡΓΑΣΤΗΡΙΟΥ #5
«Προγραμματισμός Η/Υ» - Τετράδιο Εργαστηρίου #5 2 Γενικά Στο Τετράδιο #5 του Εργαστηρίου θα ασχοληθούμε με πιο προχωρημένα θέματα υλοποίησης εφαρμογών σε C. Πιο συγκεκριμένα, θα εξοικειωθείτε με τη χρήση αλγορίθμων ταξινόμησης και αναζήτησης στοιχείων σε πίνακες, καθώς και με πιο εξελιγμένους τύπους δεδομένων (struct), μέσω των οποίων θα μπορείτε να υλοποιήσετε εφαρμογές που απαιτούν εισαγωγές, τροποποιήσεις, διαγραφές και εκτυπώσεις ενός συνόλου δεδομένων (εγγραφές) και όχι μεμονωμένων μεταβλητών. Στο πρόγραμμα που ακολουθεί, δείχνεται η διαδικασία ταξινόμησης ενός πίνακα με τη χρήση του αλγορίθμου της «φυσαλίδας» (bubble sort) καθώς και η επεξεργασία διαφόρων «πεδίων» ενός τύπου δεδομένων που ορίζει ο χρήστης (User Defined Data Structure). Πρόβλημα Μια αντιπροσωπεία εμπορίας ανταλλακτικών και μηχανολογικών εξαρτημάτων, διατηρεί μια χειρόγραφη κατάσταση, που περιέχει τα ανταλλακτικά που βρίσκονται στην αποθήκη της. Κάθε ανταλλακτικό είναι καταχωρημένο σε μια καρτέλα, όπου τηρούνται τα εξής στοιχεία: Κωδικός Ανταλλακτικού, Περιγραφή, Κατασκευαστής, Κόστος Αγοράς και Ποσότητα. Με κάθε εισαγωγή (αγορά) ή εξαγωγή (πώληση) ανταλλακτικού από την αποθήκη, ο υπεύθυνος ενημερώνει την καρτέλα του κάθε ανταλλακτικού. Ειδικότερα, κατά την εισαγωγή ενός νέου ανταλλακτικού, ο υπεύθυνος καταχωρεί (βάσει τιμολογίων) τα νέα εμπορεύματα, δημιουργώντας νέους κωδικούς («ανοίγει» νέα καρτέλα). Κατά την εξαγωγή όλης της ποσότητας κάποιου υπάρχοντος ανταλλακτικού, έστω ότι ο υπεύθυνος διαγράφει το ανταλλακτικό από την κατάσταση διαθεσίμων. Στο τέλος κάθε μέρας, συμπληρώνεται μια συνοπτική κατάσταση των προϊόντων της αποθήκης, η οποία διαβιβάζεται στο λογιστήριο. Μια τυπική ημερήσια αναφορά είναι η παρακάτω: Κωδικός Περιγραφή Κατασκευαστής Κόστος Αγοράς Ποσότητα 1001 Γρανάζι Metal Constr AEBE 14.65 15 1002 Ρουλεμάν Power Eng Ltd 10.30 10 1006 Στρόφαλος Metal Constr AEBE 62.50 6 1008 Τροφοδοτικό Bosch 100.65 18 1010 Άξονας Power Eng Ltd 55.10 3 Ζητείται: Να γράψετε ένα πρόγραμμα που να τηρεί μηχανογραφικά την αποθήκη της πιο πάνω επιχείρησης, λαμβάνοντας υπ όψιν σας τα ακόλουθα: 1. Το πρόγραμμα θα πρέπει να εμφανίζει ένα μενού επιλογής με τις ανάλογες λειτουργίες που θα επιτελεί, όπου για κάθε λειτουργία θα πρέπει να
«Προγραμματισμός Η/Υ» - Τετράδιο Εργαστηρίου #5 3 καλείται η αντίστοιχη συνάρτηση (με κατάλληλες παραμέτρους κλήσης). Οι λειτουργίες αυτές είναι: 1. Εισαγωγή Ανταλλακτικού, 2. Διαγραφή Ανταλλακτικού, 3. Εκτύπωση Ημερήσιας Αναφοράς, 4. Έξοδος από το πρόγραμμα. 2. Το κάθε ανταλλακτικό θα αναπαρίσταται με τον τύπο δεδομένων Part_record και θα πρέπει να αποτελείται από τα εξής πεδία: int code, char description[20], char manufacturer[25], float price, int quantity. 3. Στην «Εισαγωγή Ανταλλακτικού», οι εγγραφές θα πρέπει να αποθηκεύονται σε έναν πίνακα storehouse τύπου Part_record, SIZE θέσεων, έστω: Part_record storehouse[size]. Η αποθήκευση θα πρέπει να γίνεται στην πρώτη κενή θέση του πίνακα (κωδικός ανταλλακτικού = 0) και η συνάρτηση θα επιστρέφει μια ακέραια τιμή που θα δηλώνει εάν τα δεδομένα αποθηκεύθηκαν σωστά ή όχι. Μη σωστή αποθήκευση των δεδομένων έχουμε στην περίπτωση που ο πίνακας (SIZE θέσεων) είναι γεμάτος, οπότε θα πρέπει να τυπώνεται και αντίστοιχο μήνυμα αποτυχίας. 4. Στην «Διαγραφή Ανταλλακτικού», ο χρήστης θα πρέπει να πληκτρολογεί τον κωδικό του ανταλλακτικού που επιθυμεί να διαγράψει από τον πίνακα. Σε περίπτωση αποτυχίας (ο κωδικός δεν βρέθηκε) θα πρέπει να τυπώνεται κατάλληλο μήνυμα. 5. Στην «Εκτύπωση Αναφοράς» το πρόγραμμα θα πρέπει πριν εκτυπώσει τα στοιχεία του πίνακα, να τα ταξινομεί κατά αύξουσα σειρά κωδικού. Η συνάρτηση που θα υλοποιεί την ταξινόμηση του πίνακα, θα βασίζεται στον αλγόριθμο ταξινόμησης με τη μέθοδο της φυσαλίδας (bubble sort). Ανάλυση του προβλήματος Ο ορισμός του προβλήματος απαιτεί τη δήλωση ενός σύνθετου τύπου δεδομένων που θα περιέχει τα χαρακτηριστικά του κάθε ανταλλακτικού. Ο τύπος δεδομένων αυτός ονομάζεται struct (από το structure = δομή) και μπορεί, βάσει των δεδομένων του προβλήματος, να οριστεί ως εξής: typedef struct int code; char description[20]; char manufacturer[25]; float price; int quantity; Part_record; Οι πιο πάνω εντολές έχουν σαν αποτέλεσμα τον ορισμό ενός νέου τύπου δεδομένων (typedef) με το όνομα Part_record. Παρατηρείστε πως ο τύπος Part_record περιέχει όλα τα ζητούμενα στοιχεία (πεδία) του ανταλλακτικού, όπως αυτά ορίζονται στην εκφώνηση της άσκησης. Μια μεταβλητή τύπου Part_record μπορεί να μεταβιβασθεί ως παράμετρος κλήσης σε μια συνάρτηση, όπως επίσης μπορεί και να επιστραφεί από την συνάρτηση αυτή.
«Προγραμματισμός Η/Υ» - Τετράδιο Εργαστηρίου #5 4 Για την υλοποίηση των λειτουργιών της αποθήκης, πρέπει να οριστούν αντίστοιχες συναρτήσεις που θα καλούνται μέσω μιας εντολής ελέγχου πολλαπλής επιλογής (switch case) και θα επιστρέφουν κατάλληλες τιμές. Έτσι, για παράδειγμα, στον κώδικα που ακολουθεί, οι συναρτήσεις insert_part και remove_part επιστρέφουν την ακέραια τιμή 0 ή -1, ανάλογα με το αν η λειτουργία εκτελέστηκε επιτυχώς ή όχι, αντίστοιχα (βλ. κώδικα που ακολουθεί). Ένα τελευταίο ζήτημα που θα μας απασχολήσει είναι ο τρόπος επεξεργασίας των πεδίων ενός struct. Για να αναφερθούμε σε κάποιο πεδίο ενός τύπου δεδομένων struct, προσδιορίζουμε πρώτα τη μεταβλητή του τύπου και στη συνέχεια το όνομα του πεδίου που επιθυμούμε να επεξεργαστούμε (η γενική μορφή είναι: [όνομα_μεταβλητής_τύπου].[όνομα_πεδίου]). Για παράδειγμα, αν θέλουμε να εκχωρήσουμε την τιμή 0 στον κωδικό ενός ανταλλακτικού γράφουμε την εντολή: part.code = 0; όπου part είναι μεταβλητή τύπου Part_record, και code είναι το πεδίο του τύπου που αναπαριστά τον κωδικό του ανταλλακτικού.
«Προγραμματισμός Η/Υ» - Τετράδιο Εργαστηρίου #5 5 Προτεινόμενη Λύση: /* Προγραμματιστής : Όνομα Επώνυμο, Αριθμός Μητρώου Ημερομηνία συγγραφής : 24/5/2002 Λειτουργία Προγράμματος : Διαχειρίζεται μια αποθήκη ανταλλακτικών */ #include <stdio.h> #include <string.h> #define TRUE 0 #define FALSE -1 #define SIZE 4 /* Το μέγεθος του πίνακα */ typedef struct /* Ο τύπος δεδομένων που θα αποθηκεύονται τα στοιχεία του ανταλλακτικού */ int code; char description[20]; char manufacturer[25]; float price; int quantity; Part_record; Part_record part, temp; /* Δήλωση της μεταβλητής part ως τύπου Part_record */ Part_record storehouse[size]; /* Δήλωση του πίνακα των εγγραφών, ως τύπου Part_record */ void show_menu(void); /* Δήλωση των συναρτήσεων που θα χρησιμοποιήσουμε */ Part_record get_part_data(part_record part); int get_part_code(void); int insert_part(part_record part, Part_record store[]); int remove_part(int code, Part_record store[]); void sort(part_record store[]); void print_report(part_record []);
«Προγραμματισμός Η/Υ» - Τετράδιο Εργαστηρίου #5 6 main() int choice; show_menu(); scanf("%d", &choice); while (choice!=4) switch(choice) case 1: temp = get_part_data(part); if (insert_part(temp, storehouse) == TRUE) printf("\nτο ανταλλακτικό καταχωρήθηκε. Η αποθήκη ενημερώθηκε...\n"); else printf("\nτο ανταλλακτικό δεν καταχωρήθηκε. Η αποθήκη είναι γεμάτη!\n"); break; case 2: temp.code = get_part_code(); if (remove_part(temp.code,storehouse) == TRUE) printf("\nτο ανταλλακτικό διαγράφηκε. Η αποθήκη ενημερώθηκε...\n"); else printf("\nο κωδικός του ανταλλακτικού δεν υπάρχει στη αποθήκη!\n"); break; case 3: sort(storehouse); print_report(storehouse); break; case 4: break; default: printf("\nλανθασμένη Επιλογή!"); break; show_menu(); scanf("%d",&choice); /* Τέλος while */ /* Τέλος της main */
«Προγραμματισμός Η/Υ» - Τετράδιο Εργαστηρίου #5 7 void show_menu(void) /* Εμφανίζει το μενού επιλογών */ printf("\n\n******** ΔΙΑΧΕΙΡΙΣΗ ΑΠΟΘΗΚΗΣ ********\n\n"); printf("\n 1. Εισαγωγή Ανταλλακτικού"); printf("\n 2. Διαγραφή Ανταλλακτικού"); printf("\n 3. Εκτύπωση Αναφοράς"); printf("\n 4. Έξοδος\n\n"); printf("\n Επιλογή: "); return; Part_record get_part_data(part_record part) /* Δέχεται τα δεδομένα εισόδου */ printf("\n-------- ΕΙΣΑΓΩΓΗ ΑΝΤΑΛΛΑΚΤΙΚΟΥ --------\n"); printf("\nκωδικός : "); scanf("%d", &part.code); printf("περιγραφή : "); scanf("%s", part.description); printf("κατασκευαστής: "); scanf("%s", part.manufacturer); printf("κόστος Αγοράς: "); scanf("%f", &part.price); printf("ποσότητα : "); scanf("%d", &part.quantity); return(part); int get_part_code(void) int code; printf("\n-------- ΔΙΑΓΡΑΦΗ ΑΝΤΑΛΛΑΚΤΙΚΟΥ --------\n"); printf("\nκωδικός : "); scanf("%d", &code); return(code);
«Προγραμματισμός Η/Υ» - Τετράδιο Εργαστηρίου #5 8 int insert_part(part_record part, Part_record store[]) ανταλλακτικό στο πίνακα */ int i=0, found=false; /*Καταχωρεί το while (i<size && found == FALSE) if (store[i].code == 0) store[i].code = part.code; strcpy(store[i].description,part.description); strcpy(store[i].manufacturer, part.manufacturer); store[i].price = part.price; store[i].quantity = part.quantity; found = TRUE; i++; return(found); int remove_part(int code,part_record store[]) int i=0, found=false; /* Διαγράφει ένα ανταλλακτικό από την αποθήκη */ while (i<size && found == FALSE) if (store[i].code == code) store[i].code = 0; strcpy(store[i].description, " "); strcpy(store[i].manufacturer, " "); store[i].price = 0.00; store[i].quantity = 0; found = TRUE; i++; return(found);
«Προγραμματισμός Η/Υ» - Τετράδιο Εργαστηρίου #5 9 void sort(part_record store[]) int i, pass; Part_record hold; /* Ταξινομεί τον πίνακα της αποθήκης με τη μέθοδο της φυσαλίδας */ for (pass = 0; pass < SIZE; pass++) for (i=0; i< SIZE-1; i++) if (store[i].code > store[i+1].code) hold = store[i]; store[i] = store[i+1]; store[i+1] = hold; void print_report(part_record store[]) /* Τυπώνει την ημερήσια αναφορά */ int i; printf("\n********************************* ΕΚΤΥΠΩΣΗ ΗΜΕΡΗΣΙΑΣ ΑΝΑΦΟΡΑΣ ********************************************\n"); printf("\na/a Κωδικός Περιγραφή Κατασκευαστής Κόστος Ποσότητα\n\n"); for (i=0; i<size; i++) printf("%-2d\t%-5d\t\t%-20s\t\t%-25s%.2f\t\t%- 5d\n",i+1,store[i].code,store[i].description,store[i].manufacturer,store[i].price,stor e[i].quantity); printf("\n*********************************************************** ***********************************************\n");