ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ & ΤΕΧΝΟΛΟΓΙΑΣ ΥΠΟΛΟΓΙΣΤΩΝ Τεχνολογικό Εκπαιδευτικό Ίδρυμα Λαμίας ΤΕΙ ΛΑΜΙΑΣ ΕΡΓΑΣΤΗΡΙΑΚΕΣ ΑΣΚΗΣΕΙΣ ΤΟΥ ΜΑΘΗΜΑΤΟΣ «ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ Ι» – ΓΛΩΣΣΑ C Δρ. ΠΑΠΑΓΕΩΡΓΙΟΥ ΕΛΠΙΝΙΚΗ ΚΑΘΗΓΗΤΡΙΑ ΕΦΑΡΜΟΓΩΝ ΣΕΠΤΕΜΒΡΙΟΣ 2010 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας 1η Εργαστηριακή Ασκηση Προγραμματισμού Ι - Γλώσσα C Σκοπός: ¾ Γνωριμία με τη γλώσσα προγραμματισμού C, το περιβάλλον της και τον compiler της C που χρησιμοποιείται στο εργαστήριο. ¾ Βασική δομή ενός προγράμματος ¾ Δημιουργία, μεταγλώττιση και εκτέλεση απλών προγραμμάτων Μπείτε στο λογαριασμό σας και φτιάξτε ένα φάκελο μέσα στον οποίο θα γράφετε όλα τα προγράμματα για το εργαστήριο. Μπορείτε να τον ονομάσετε ProgI ή κάποιο άλλο αντιπροσωπευτικό όνομα. Μέσα σε αυτό το φάκελο φτιάξτε έναν γι'αυτό το πρώτο εργαστήριο. Μπορείτε να τον ονομάσετε lab1 ή κάποιο άλλο αντιπροσωπευτικό όνομα. Ανοιξτε τη Microsoft Visual C++ που είναι εγκατεστημένη στους υπολογιστές του εργαστηρίου, ή όποιο άλλο προγραμματιστικό περιβάλλον είναι εγκατεστημένο για τη C (περαιτέρω πληροφορίες θα δοθούν στο εκάστοτε εργαστήριο), δημιουργήστε ένα νέο project (empty workspace) και στη συνέχεια δημιουργήστε ένα νέο αρχείο για να γράψετε το πρόγραμμά σας (newÆ C++ source file). Θα δώσετε ένα όνομα στο αρχείο που θα δημιουργήσετε για την 1η εργαστηριακή άσκηση το οποίο θα έχει την επέκταση .cpp (π.χ. askisi1.cpp). Header files και η ντιρεκτίβα του προεπεξεργαστή (preprocessor) #include #include <stdio.h> Δομή ενός προγράμματος σε C Εντολές προεπεξεργαστή Δηλώσεις συναρτήσεων Δηλώσεις μεταβλητών Κυρίως πρόγραμμα Ορισμοί συναρτήσεων Κυρίως Πρόγραμμα int main ( ) { - δηλώσεις μεταβλητών - προτάσεις γλώσσας } Είσοδος δεδομένων Επεξεργασία δεδομένων Έξοδος αποτελεσμάτων Συναρτήσεις εισόδου/εξόδου π.χ. printf(“αλφαριθμητικό”); Δρ. Ελπινίκη Παπαγεωργίου 2 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας Χρήση σχολίων και αναγνωσιμότητα προγράμματος /* Εισαγωγή σχολίων στο πρόγραμμα σας είναι απαραίτητη για τον Καλό /* /* Προγραμματισμό! */ Γράφοντας το πρώτο πρόγραμμα σε C: Hello world! Είστε έτοιμοι να γράψετε το παρακάτω πρόγραμμα το οποίο εκτυπώνει στην οθόνη το μήνυμα Hello world! /* Display the message "Hello world!" on the screen */ #include <stdio.h> int main () { printf("Hello world!\n"); return 0; } Σώστε το αρχείο με όνομα hello_world.cpp στο φάκελο που φτιάξατε γι'αυτό το εργαστήριο. Στη συνέχεια μεταγλωττίστε (compile) και εκτελέστε (execute) το πρώτο πρόγραμμά σας. Αν δεν υπάρχουν λάθη, ο compiler θα παράγει ένα εκτελέσιμο πρόγραμμα. Τι παρατηρείτε??? Ασκηση Γράψτε ένα πρόγραμμα το οποίο κάνει το εξής: ¾ Εκτυπώνει στην οθόνη το Όνομα και το Επιθετό σας, τον ΑΜ σας και το Τμήμα στο οποίο ανήκετε, σε διαφορετικές γραμμές το καθένα με την χρήση του ′\n′. Δρ. Ελπινίκη Παπαγεωργίου 3 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας 2η Εργαστηριακή Ασκηση Προγραμματισμού Ι - Γλώσσα C Σκοπός: ¾ Εξάσκηση στη βασική είσοδο / έξοδο ¾ Εξάσκηση στη δήλωση και χρήση μεταβλητών ¾ Αναγνώριση και διόρθωση τυπικών συντακτικών και σημασιολογικών λαθών Ανοίξτε το περιβάλλον προγραμματισμού της C (π.χ. Microsoft Visual C++). Δημιουργήστε ένα κενό αρχείο (π.χ. lab2.cpp). Σε αυτό θα γράψετε το πρόγραμμά σας. ΕΙΣΟΔΟΣ/ΕΞΟΔΟΣ (scanf/printf) Είσοδος Δεδομένων (& Æ τελεστής διεύθυνσης) ¾ Εντολή/Συνάρτηση scanf: scanf (“<προσδιοριστής>”, &<μεταβλητή>); ¾ Είσοδος ακεραίων: scanf (“%d”, &num); ¾ Είσοδος πραγματικών: scanf (“%f”, &num); Προσδιοριστές: %f, %e, %g ¾ Είσοδος χαρακτήρων: scanf (“%c”, &ch); ¾ % - Κωδικός μορφοποίησης ¾ Άλλοι κωδικοί: %c για χαρακτήρες και %f για αριθμούς κινητής υποδιαστολής Εξοδος αποτελεσμάτων: ¾ Εντολή/Συνάρτηση printf: printf (“<περιγραφή>”, <ακολουθία μεταβλητών>); ¾ Έξοδος ακεραίων: printf (“%d”, num); Προσδιοριστές: %d, %x, %o ¾ Έξοδος πραγματικών: printf (“%f”, num); Προσδιοριστές: %f, %e, %g ¾ Έξοδος χαρακτήρων: printf (“%c”, ch); (χαρακτήρας) printf (“%d”, ch); (Κωδικός ASCII) Προσδιοριστές: %c, %d ¾ Προσδιοριστές μορφής εκτύπωσης Οθόνης: ‘\t’, ‘\n’ Αριθμών: %<ακέρ><προσδιορ> (καθορισμός πλάτους πεδίου). Π.χ. %3d %[<ακέρ>][.<ακέρ>]<προσδιορ> (καθορισμός πλάτους πεδίου και δεκαδικών ψηφίων). Π.χ. %6.1f, %.2f, %6f ΔΗΛΩΣΗ ΜΕΤΑΒΛΗΤΩΝ & ΕΚΧΩΡΗΣΗ ΤΙΜΩΝ Κάθε μεταβλητή, σταθερά έχει ένα τύπο Δρ. Ελπινίκη Παπαγεωργίου 4 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας τύπος όνοµα-µεταβλητής; Τύπος Δεσµευµένη λέξη χαρακτήρας char προσηµασµένος ακέραιος int αριθµός κινητής υποδιαστολής float αριθµός κινητής υποδιαστολής διπλής ακρίβειας double απουσία τιµής void • Ο τύπος καθορίζει το μέγεθος του «κουτιού» που θα δεσμευτεί στη μνήμη – char: 1 byte – int: 4 bytes – float: 4 bytes – double: 8 bytes • Προσδιοριστές – short int: 2 bytes – long int: 8 bytes – long double: .. bytes • Προσδιοριστές: signed, unsigned • unsigned int, unsigned char – 32 bits, 8 bits – 0…232-1, 0…28-1 • signed int, signed char – 31 bits, 7 bits – -231…231-1, -27…27-1 ¾ Πολλαπλή δήλωση μεταβλητών Π.χ. float x, y, z; ¾ Ονοματολογία μεταβλητών όμοια με συναρτήσεις (0-9 όχι στην αρχή, γράμματα αλφαβήτου και κάτω παύλα) ¾ Η C είναι case-sensitive Π.χ. int count, COUNT; ¾ Eκχώρηση τιμών (αποτελεί εντολή): όνομα-μεταβλητής = τιμή; Παράδειγματα: counter = 100; fl = 100.1; fl = 100.0; ¾ Κάτι ακόμα για τη συνάρτηση εξόδου printf() printf("This prints the number %d", 99); printf("This displays %d, too", 99); Δρ. Ελπινίκη Παπαγεωργίου 5 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας Παράδειγµα 1 #include <stdio.h> int main(void) { char ch; int i; float f; double d; ch=’A’; i=10; f=100.1; d=150.2; printf("ch is %c, ", ch); printf("i is %d, ", i); printf("f is %f, ", f); printf("d is %f.", d); return 0; } ΕΙΣΟΔΟΣ ΑΡΙΘΜΩΝ ΑΠΟ ΤΟ ΠΛΗΚΤΡΟΛΟΓΙΟ ¾ scanf(“%d”, &όνομα-μεταβλητής-int); Π.χ. int num; scanf("%d", &num); ¾ scanf(“%f”, &όνομα-μεταβλητής-float); Π.χ. float fl; scanf("%f", &fl); ¾ scanf(“%lf”, &όνομα-μεταβλητής- double); Π.χ. double dbl; scanf("%lf", &dbl); Παράδειγµα 2 #include <stdio.h> int main(void) { int num; float f; double d; printf("Enter an integer: "); scanf("%d", &num); printf("Enter a floating point number: "); scanf("%f", &f); printf("Enter a floating point number (double): "); scanf("%lf", &d); } printf("%d ", num); printf("%f ", f); printf("%f", d); return 0; Δρ. Ελπινίκη Παπαγεωργίου 6 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας ΑΡΙΘΜΗΤΙΚΕΣ ΕΚΦΡΑΣΕΙΣ -Αριθµητικοί τελεστές της C Η C ορίζει ένα εκτεταμένο σύνολο αριθμητικών τελεστών: Προτεραιότητα Υψηλότερη ( ) */% Χαµηλότερη + Παράδειγμα 3: #include <stdio.h> int main(void) { printf("%d", 5/2); printf(" %d", 5%2); printf(" %d", 4/2); printf(" %d", 4%2); return 0; } Παράδειγµα 4 /* Αυτό είναι ένα πρόγραµµα υπολογισµού του όγκου σφαίρας όταν δίνεται η ακτίνα της. */ #include <stdio.h> int main(void) { float pi, r, v; /* δήλωση µεταβλητών */ pi = 3.141592; /* ο αριθµός π */ printf("Enter radius: "); scanf("%f", &r); /* είσοδος της ακτίνας */ v=(4.0 * pi * r * r * r) / 3.0 ; /* υπολογισµός όγκου */ printf("Volume is %f", v); /* εµφάνιση αποτελέσµατος */ return 0; } Εντολή Return ¾ Στην εντολή return, η συνάρτηση επιστρέφει (τερματίζει) αμέσως. ¾ Καμία εντολή μετά δεν εκτελείται. ¾ Η τιμή της return μπορεί να είναι οποιαδήποτε έγκυρη έκφραση της C. ¾ Xωρίς τιμή η Return ; Κυρίως σε συναρτήσεις τύπου void. Δρ. Ελπινίκη Παπαγεωργίου 7 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας Ασκήσεις στο Εργαστήριο 1. Λήψη δυο ακέραιων θετικών αριθμών από το πληκτρολόγιο, έστω a και b, και εμφάνιση της διαφοράς (a-b) και του γινομένου (a·b). 2. Γράψτε ένα πρόγραµµα το οποίο θα υπολογίζει τον όγκο ενός ορθογώνιου παραλληλεπίπεδου. Το πρόγραµµα σας θα πρέπει να ζητά τις διαστάσεις του ορθογώνιου από τον χρήστη. Χρησιµοποιήστε σχόλια για να εξηγήσετε την ροή του προγράµµατος. 3. Γράψτε ένα πρόγραμμα το οποίο κάνει τα εξής: ¾ Εκτυπώνει στην οθόνη το μήνυμα “How many students are there in a lab?” ¾ Διαβάζει από το πληκτρολόγιο το πλήθος των φοιτητών ενός εργαστηρίου. ¾ Εκτυπώνει στην οθόνη το μήνυμα “How many labs are there?” ¾ Διαβάζει από το πληκτρολόγιο το πλήθος των εργαστηρίων. ¾ Εκτυπώνει στην οθόνη το μήνυμα “There are X labs and Y students in a lab”, όπου X είναι το πλήθος των φοιτητών και Υ το πλήθος των εργαστηρίων. ¾ Εκτυπώνει στην οθόνη το μήνυμα “There are Z students total.”, όπου Ζ είναι το γινόμενο του πλήθους των φοιτητών επί του πλήθους των εργαστηρίων. Παρατηρείστε πως για να λειτουργήσει το πρόγραμμά σας θα χρειαστεί να δηλώσετε κατάλληλες μεταβλητές. Φροντίστε οι μεταβλητές σας να έχουν περιγραφικά ονόματα όπως περιγράφεται στις σημειώσεις του μαθήματος. Επιπλέον, το πρόγραμμά σας πρέπει να έχει σωστή στοίχιση και σχόλια. Το πρόγραμμά σας πρέπει να μεταγλωτίζεται χωρίς λάθη ή προειδοποιήσεις και να εκτελείται ακριβώς όπως περιγράφεται πιο πάνω. Δρ. Ελπινίκη Παπαγεωργίου 8 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας 3η Εργαστηριακή Ασκηση Προγραμματισμού Ι - Γλώσσα C Σκοπός: ¾ Σχεσιακοί και Λογικοί Τελεστές ¾ Κατανόηση των εντολών if (συνθήκη) εντολή1 else εντολή2 ¾ και των μακροεντολών getchar(); putchar(); ¾ Ενθεση εντολών If Σχεσιακοί και λογικοί τελεστές Σχεσιακοί τελεστές της C Τελεστής > >= < <= == != Ενέργεια µεγαλύτερο από µεγαλύτερο από ή ίσο µε µικρότερο από µικρότερο από ή ίσο µε ίσο µε άνισο (διάφορο) Λογικοί τελεστές της C Τελεστής && || ! Ενέργεια AND OR NOT Προτεραιότητα σχεσιακών και λογικών τελεστών Υψηλότερη ! > >= < <= == != && Χαµηλότερη || ΠΑΡΑΔΕΙΓΜΑΤΑ ΛΟΓΙΚΩΝ & ΣΧΕΣΙΑΚΩΝ ΤΕΛΕΣΤΩΝ Παράδειγμα: p=0, q=1 Æ p&&q=0, p||q=1, !p=1 Παράδειγµα 1 #include <stdio.h> int xor(int a, int b); int main(void) { int p, q; printf("enter P (0 or 1): "); scanf("%d", &p); printf("enter Q (0 or 1): "); scanf("%d", &q); printf("P AND Q: %d\n", p && q); printf("P OR Q: %d\n", p || q); printf("P XOR Q: %d\n", xor(p, q)); Δρ. Ελπινίκη Παπαγεωργίου 9 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας } return 0; int xor(int a, int b) { return (a || b) && !(a && b); } Έλεγχος της ροής εκτέλεσης των προγραμμάτων (IF) if(έκφραση) εντολή; if(έκφραση) εντολή1; else εντολή2; αν η έκφραση είναι true (≠0) η εντολή θα εκτελεστεί αν η έκφραση είναι false (=0) η εντολή θα αγνοηθεί if(έκφραση){ εντολή1; εντολή2; τµήµα κώδικα (code block) : εντολήΝ; } else{ εντολή1; εντολή2; το τµήµα else είναι προαιρετικό : εντολήΜ; } Παράδειγµα 2 #include <stdio.h> int main(void) { int num1, num2; printf("Enter first number: "); scanf("%d", &num1); printf("Enter second number: "); scanf("%d", &num2); } if(num2 == 0) printf("Cannot divide by zero."); else printf("Answer is: %d.", num1 / num2); return 0; Παράδειγµα 3: Έστω µία µη συνεχής συνάρτηση που ορίζεται µε το παρακάτω τµήµα κώδικα. float f(float x) { float value; if(x < 0) value = - x; else value = x; return value; Δρ. Ελπινίκη Παπαγεωργίου 10 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας } Είσοδος χαρακτήρων από το πληκτρολόγιο • Η getchar() χρησιμοποιεί line buffer και αναμένει το Enter για να επιστρέψει τον χαρακτήρα. char ch; ch = getchar(); printf(" you typed: %c", ch); • H getche() χωρίς temp line character buffer επιστρέφει αμέσως τον χαρακτήρα (conio.h) Παράδειγµα 4 #include <stdio.h> int main(void) { int a, b; char ch; printf("Do you want to:\n"); printf("Add, Subtract, Multiply, or Divide?\n"); printf("Enter first letter: "); ch = getchar(); printf("\nEnter first number: "); scanf("%d", &a); printf("Enter second number: "); scanf("%d", &b); } if(ch=='A') printf("%d", a+b); if(ch=='S') printf("%d", a-b); if(ch=='M') printf("%d", a*b); if(ch=='D' && b!=0) printf("%d", a/b); Παράδειγµα 5 #include <conio.h> #include <stdio.h> int main(void) { char ch; printf("Enter a character: "); ch = getche(); printf("\nIts ASCII code is %d", ch); return 0; } #include <conio.h> γιατί το αρχείο conio.h περιέχει το πρωτότυπο της συνάρτησης getche(). Ένθεση εντολών if (ή φωλιασμένα if) Η δεύτερη if είναι ένθετη (nested) µέσα στην πρώτη. Κλίµακα if-else-if if(έκφραση) εντολή; else if(έκφραση) εντολή; else if(έκφραση) εντολή; : : else εντολή; Δρ. Ελπινίκη Παπαγεωργίου 11 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας Παράδειγµα 6 #include <stdio.h> int main(void) { int a, b; char ch; printf("Do you want to:\n"); printf("Add, Subtract, Multiply, or Divide?\n"); printf("Enter first letter: "); ch = getchar(); printf("\nEnter first number: "); scanf("%d", &a); printf("Enter second number: "); scanf("%d", &b); if(ch=='A') printf("%d", a+b); else if(ch=='S') printf("%d", a-b); else if(ch=='M') printf("%d", a*b); else if(ch=='D' && b!=0) printf("%d", a/b); return 0; Ασκήσεις 1. Να γίνει ένα πρόγραμμα που να διαβάζει έναν χαρακτήρα από το πληκτρολόγιο και να εμφανίζει τον αντίστοιχο αριθμό ASCII σε δεκαδική, οκταδική και δεκαεξαδική μορφή. 2. Τι αποτελέσματα δίνουν οι παρακάτω πράξεις; x = 1+2*3+10/4; y = (7/3-2)*5; z = (7.0/2-2)*4; w = 2*4-16%5+2-2/3; 3. Να γραφεί ένα πρόγραμμα το οποίο να διαβάζει έναν ακέραιο, να ελέγχει αν είναι άρτιος ή περιττός (μονός ή ζυγός) και να εμφανίζει το αντίστοιχο μήνυμα. 4. Να γίνει ένα πρόγραμμα το οποίο να δέχεται μια χρονολογία από το πληκτρολόγιο να διαπιστώνει αν το έτος αυτό είναι δίσεκτο ή όχι και να επιστρέφει το κατάλληλο μήνυμα. 5. Να γίνει ένα πρόγραμμα που θα ζητάει από το χρήστη να πληκτρολογήσει το ύψος του σε εκατοστά του μέτρου και ανάλογα με αυτό θα του επιστρέφει έναν χαρακτηρισμό σύμφωνα με τις παρακάτω συνθήκες: ύψος < 150 ⇒ Είσαι κοντός 150 ≤ ύψος ≤ 180 ⇒ Είσαι μέτριος 180 < ύψος ⇒ Είσαι ψηλός [με απλά και με φωλιασμένα if] 6. Γράψτε ένα πρόγραμμα το οποίο θα υπολογίζει το εμβαδόν ενός κύκλου, ενός ορθογωνίου ή ενός τριγώνου. Χρησιμοποιήστε μία κλίμακα if-else-if. Δρ. Ελπινίκη Παπαγεωργίου 12 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας 4η Εργαστηριακή Ασκηση Προγραμματισμού Ι - Γλώσσα C Σκοπός: ¾ Κατανόηση της εντολής for (αρχικοποίηση; συνθήκη; βήμα) ¾ Εντολή switch ¾ Κατανόηση των βρόχων while and do-while ΧΡΗΣΗ ΤΗΣ for for (αρχικοποίηση; συνθήκη; βήμα) π.χ. for(count=1; count<11; count++) {εντολές}; Παράδειγµα #include <stdio.h> int main(void) { int answer, count; int again; for(count=1; count<11; count++) { printf("What is %d + %d? ", count, count); scanf("%d", &answer); if(answer == count+count) printf("Right!\n"); else { printf("Sorry, you're wrong\n"); printf("Try again.\n "); printf("\nWhat is %d + %d? ", count, count); scanf("%d", &answer); if(answer == count+count) printf("Right!\n"); else printf("Wrong, the answer is %d\n", count+count); } } return 0; } ΟΙ ΠΑΡΑΛΛΑΓΕΣ ΤΟΥ ΒΡΟΧΟΥ for /*Συνθήκη ελέγχου*/ #include <stdio.h> int main(void) { int i; char ch = 'a'; /* give ch an initial value */ for(i=0; ch != 'q'; i++) { printf("pass: %d\n", i); ch = getchar(); } return 0; } /*Κενό προορισμό*/ #include <stdio.h> int main(void) Δρ. Ελπινίκη Παπαγεωργίου 13 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας { char ch; for (ch=getchar(); ch!='q'; ch=getchar()); printf("Found the q."); return 0; } //ΠΡΟΓΡΑΜΜΑ που εκτυπώνει το χαρακτήρα που θα δίνετε κάθε φορά, μέχρι 10 //φορές #include <stdio.h> int main(void) { int i; char ch; for(i=0; i<10; ch=getchar()) { printf("Dwse ena xaraktira”); ch = getchar(); printf(“o xarakthras einai %c”, ch); i=i+1; } return 0; } Χρήση της switch Πολλαπλές εναλλακτικές επιλογές µε την switch switch(µεταβλητή){ case σταθερά1: αλληλουχία εντολών break; case σταθερά2: αλληλουχία εντολών break; : : default: αλληλουχία εντολών break; } Η σταθερά είναι ακέραιος ή χαρακτήρας. Η χρήση της default και break είναι προαιρετική. switch (choice) { case 1: x = a + break; case 2: x = a – break; case 3: x = a * break; case 4: x = a / b; b; b; b; Δρ. Ελπινίκη Παπαγεωργίου 14 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας break; default: printf (“Ανύπαρκτη επιλογή”); break; } Παράδειγµα #include <stdio.h> int main(void) { int a, b; char ch; printf("Do you want to:\n"); printf("Add, Subtract, Multiply, or Divide?\n"); printf("Enter first letter: "); ch = getchar(); printf("\n"); printf("Enter first number: "); scanf("%d", &a); printf("Enter second number: "); scanf("%d", &b); switch(ch) { case 'A': printf("%d", a+b); break; case 'S': printf("%d", a-b); break; case 'M': printf("%d", a*b); break; case 'D': if(b!=0) printf("%d", a/b); } return 0; } ΒΡΟΧΟΙ WHILE ΚΑΙ DO-WHILE while (<εκφραση>) {πρόταση} while (count<limit) { count++; printf(“count is %d\n”,count); } < επόμενη πρόταση> do {πρόταση} while(<εκφραση>) do { count++; printf(“count is %d\n”,count); } while (count<limit) <επόμενη πρόταση> Παράδειγµα Δρ. Ελπινίκη Παπαγεωργίου 15 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας #include <stdio.h> #include <conio.h> int main(void) { char ch; printf("Enter your message.\n"); ch = getche(); while(ch != '\r') { printf("%c", ch+1); ch = getche(); } return 0; } Τι θα εκτυπώσει το παραπάνω πρόγραμμα? Παράδειγµα #include <stdio.h> int main(void) { int total, i, j; total = 0; do { printf("Enter next number (0 to stop): "); scanf("%d", &i); printf("Enter number again: "); scanf("%d", &j); if(i != j) { printf("Mismatch\n"); continue; } total = total + i; } while(i); printf("Total is %d\n", total); return 0; } Ασκήσεις για λύση 1. Να φτιάξετε πρόγραμμα που να διαβάζει το μέσο όρο βαθμολογίας(ΜΟ) ενός σπουδαστή στα ΤΕΙ και αν είναι σωστός (0<=ΜΟ<=10) να εμφανίζει: ‘FAIL’ αν 0<=ΜΟ<5 ’GOOD’ αν 5<=ΜΟ<6,5 ’VERY GOOD’ αν 6,5<=ΜΟ<8,5 ’EXCELLENT’ αν 8,5<=ΜΟ<10 Αλλιώς να εμφανίζει το μήνυμα «WRONG GRADE” 2. Με το νέο σύστημα πληρωμής των διοδίων, οι οδηγοί των τροχοφόρων έχουν τη δυνατότητα να πληρώνουν το αντίτιμο των διοδίων µε ειδική μαγνητική κάρτα. Υποθέστε ότι υπάρχει μηχάνημα το οποίο διαθέτει είσοδο για την κάρτα και φωτοκύτταρο. Το μηχάνημα διαβάζει από την κάρτα το υπόλοιπο των χρημάτων και το αποθηκεύει σε µία μεταβλητή Υ και, µε το φωτοκύτταρο, αναγνωρίζει τον τύπο του τροχοφόρου και το αποθηκεύει σε µία μεταβλητή Τ. Δρ. Ελπινίκη Παπαγεωργίου 16 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας Υπάρχουν τρεις τύποι τροχοφόρων: δίκυκλα (D), επιβατικά (E) και φορτηγά (F), µε αντίτιμο διοδίων 1, 2 και 3 ευρώ αντίστοιχα. Να αναπτύξετε πρόγραμμα, το οποίο: α. ελέγχει τον τύπο του τροχοφόρου και εκχωρεί στη μεταβλητή Α το αντίτιμο των διοδίων, ανάλογα µε τον τύπο του τροχοφόρου β. ελέγχει την πληρωμή των διοδίων µε τον παρακάτω τρόπο. Αν το υπόλοιπο της κάρτας επαρκεί για την πληρωμή του αντιτίμου των διοδίων, αφαιρεί το ποσό αυτό από την κάρτα. Αν η κάρτα δεν έχει υπόλοιπο, το μηχάνημα ειδοποιεί µε μήνυμα για το ποσό που πρέπει να πληρωθεί. Αν το υπόλοιπο δεν επαρκεί, μηδενίζεται η κάρτα και δίνεται µε μήνυμα το ποσό που απομένει να πληρωθεί. 3. Να γίνει ένα πρόγραμμα το οποίο θα ζητάει ακέραιους αριθμούς μέχρι να λάβει την τιμή 0 (μηδέν). Γι’ αυτούς τους αριθμούς (με εξαίρεση του μηδενός) θα υπολογίζει το άθροισμα, το πλήθος και τη μέση τιμή. Επίσης θα επιστρέφει την τιμή του μεγαλύτερου και του μικρότερου. 4. Δημιουργήστε ένα πρόγραμμα που να τυπώνει την προπαίδεια όλων των ακεραίων από το 1 μέχρι το 10. 5. Να γίνει ένα πρόγραμμα που θα γεμίζει ένα γραμμικό πίνακα ακεραίων 10 στοιχείων, με τιμές από το πληκτρολόγιο και θα τον εμφανίζει σε μια γραμμή. [με for και με do – while] 6. Να γίνει ένα πρόγραμμα που θα γεμίζει ένα γραμμικό πίνακα ακεραίων 15 στοιχείων, με τυχαίες τιμές [με την βοήθεια της random]. Κατόπιν, να ζητάει ένα ακέραιο από το πληκτρολόγιο, να υπολογίζει και να αποθηκεύει σε έναν άλλο πίνακα το γινόμενο του πρώτου πίνακα με τον ακέραιο αυτό και τέλος να εμφανίζει στην οθόνη τον αρχικό πίνακα και τον πίνακα του γινομένου σε μια γραμμή τον καθένα. 7. Να φτιάξετε πρόγραμμα που να διαβάζει έναν ακέραιο αριθμό Ν και να εμφανίζει στην οθόνη ένα δέντρο με Ν γραμμές από αστεράκια. Π.χ. αν Ν=4 θα πρέπει να εμφανίζεται το παρακάτω σχήμα: * *** ***** ******* Παρατήρηση: Η ι-οστή γραμμή έχει Ν-ι κενά και 2*ι-1 αστεράκια Δρ. Ελπινίκη Παπαγεωργίου 17 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας 5η Εργαστηριακή Ασκηση Προγραμματισμού Ι - Γλώσσα C Σκοπός: ¾ Επανάληψη στη χρήση των δομών ελέγχου ¾ Χρήση Πινάκων (arrays) Επαναληπτική άσκηση στις δομές ελέγχου Γράψτε ένα πρόγραμμα το οποίο θα χρησιμοποιηθεί για τη διαχείριση των βαθμών στο εργαστήριο ενός μαθήματος. Γνωρίζουμε ότι το εργαστήριο έχει 10 φοιτητές και ότι οι βαθμοί είναι πραγματικοί αριθμοί μεταξύ 0 και 100. Το πρόγραμμά σας πρέπει να κάνει τα εξής: ● Ορίζει ένα πίνακα στον οποίο θα αποθηκευτούν οι βαθμοί ● Διαβάζει από το πληκτρολόγιο τους βαθμούς των φοιτητών και τους αποθηκεύει στον πίνακα ● Εκτυπώνει τους βαθμούς στην οθόνη, έναν σε κάθε γραμμή (με 2 δεκαδικά ψηφία) #include<stdio.h> #define CLASS_SIZE 10 int main (int argc, char *argv[]) { double scores[CLASS_SIZE]; char doAverage; int i; double sum, average; /* read data */ for (i=0; i < CLASS_SIZE; i++) { printf("Enter score: "); scanf("%lf", &scores[i]); if (scores[i] < 0 || scores[i] > 100) { printf("Error: Invalid value.\n"); return (1); } } /* print data */ for (i=0; i < CLASS_SIZE; i++) { printf("%6.2f\n", scores[i]); } /* request to compute average */ do { printf("Compute average? (y/n)"); scanf(" %c", &doAverage); } while (doAverage != 'y' && doAverage != 'n'); /* compute and display average, if requested */ if (doAverage == 'y') { sum = 0; for (i=0; i<CLASS_SIZE; i++) { sum += scores[i]; } average = sum / CLASS_SIZE; printf("%.2f\n", average); } Δρ. Ελπινίκη Παπαγεωργίου 18 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας return 0; } Συνέχεια άσκησης για το εργαστήριο Προσθέστε κώδικα στο πρόγραμμά σας ώστε να ● Για κάθε βαθμό που διαβάζει, ελέγχει ότι είναι μεταξύ 0 και 100. Αν κάποιος βαθμός δεν είναι εντός τον ορίων, το πρόγραμμα εκτυπώνει το μήνυμα "Error: Invalid grade" και τερματίζει. ● Αφού εκτυπώσει τους βαθμούς, εκτυπώνει το μήνυμα "Compute average? (y/n)" και διαβάζει την απάντηση του χρήστη η οποία πρέπει να είναι είτε ο χαρακτήρας 'y' είτε ο χαρακτήρας 'n'. Αν η απάντηση είναι οποιοσδήποτε άλλος χαρακτήρας, το πρόγραμμα ξαναρωτά έως ότου δοθεί έγκυρη απάντηση. ● Αν η απάντηση ήταν 'y', υπολογίζει και εκτυπώνει το μέσο όρο των βαθμών, διαφορετικά τερματίζει. Πίνακες 'Ενας πίνακας (array) στη C είναι ένας αριθμός από ομοειδή δεδομένα στο καθένα από τα οποία μπορούμε να αναφερθούμε με το όνομα του πίνακα και τον αύξοντα αριθμό του μέσα στον πίνακα (array). Για να δηλώσουμε έναν πίνακα χρησιμοποιούμε μία δήλωση της μορφής: τύπος_δεδομένου όνομα[πλήθος_στοιχείων]; τύπος όνομα_πίνακα[μέγεθος] int pinakas[10]; Π.χ. float bathmos[5]; Αρχικοποίηση πίνακα float bathmos[5]= {10, 8, 12.5, 15.5, 14}; float bathmos[] = {10, 8, 12.5, 15.5, 14}; (προσοχή στο πλήθος των αρχικών τιμών) Το πλήθος_στοιχείων θα πρέπει να είναι ακέραια σταθερά (μεγαλύτερη του μηδενός) ή σταθερή έκφραση. Ο πίνακας είναι μια δομή τυχαίας προσπέλασης. Δρ. Ελπινίκη Παπαγεωργίου 19 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας bathmos 0 1 2 3 4 10 8 12.5 15.5 14 bathmos[0] bathmos[1] Δείκτες θέσεων bathmos[4] … Μεταβλητές με δείκτες Δείκτης θέσης Με τον όρο αναφορά εννοούμε ότι μπορούμε να χρησιμοποιήσουμε την τιμή του στοιχείου σε μία έκφραση (π.χ. όνομα[2] + 6) ή να αλλάξουμε την τιμή του μέσω μιας έκφρασης-εκχώρησης (π.χ. όνομα[2] = 14;). 'Ενα array μπορεί, όπως και μία μεταβλητή, να αρχικοποιείται, μόνο όμως όταν η δήλωσή του βρίσκεται έξω από κάθε συνάρτηση, δεν μπορούμε δηλαδή να αρχικοποιήσουμε ένα array το οποίο δηλώνεται ως τοπικό δεδομένο σε μία συνάρτηση ή σε μία σύνθετη εντολή. Υλοποιήστε στον επεξεργαστή της C τα ακόλουθα παραδείγματα: Παράδειγμα 1 #include <stdio.h> int main(void) { int a1[10], a2[10]; int i; for(i=1; i<11; i++) a1[i-1] = i; for(i=0; i<10; i++) a2[i] = a1[i]; for(i=0; i<10; i++) printf("%d ", a2[i]); return 0; } /*Άσκηση: Αντιγραφή και αντεστραμμένα*/ Παράδειγμα 2 /* Να καταχωρηθούν ακέραιες τιμές σ’ έναν πίνακα 10 θέσεων και να βρεθεί η μέγιστη και η ελάχιστη τιμή του πίνακα καθώς και η μεταξύ τους διαφορά */ #include <stdio.h> main() { int i, a[10], max, min; clrscr(); /* καταχώρηση τιμών */ for (i=0; i<10; i++) { Δρ. Ελπινίκη Παπαγεωργίου 20 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας printf("\nΔώσε το %dο στοιχείο του πίνακα : ", i); scanf("%d", &a[i]); } /* end of for */ max = a[0]; min = a[0]; for (i=1; i<10; i++) { if (a[i] > max) max = a[i]; if (a[i] < min) min = a[i]; } /* end of for */ printf("\nΗ μέγιστη τιμή του πίνακα είναι : %d", max); printf("\nΗ ελάχιστη τιμή του πίνακα είναι : %d", min); printf("\nΗ διαφορά μέγιστης και ελάχιστης τιμής είναι : %d", \ max-min); scanf("%d", &i); } /* end of main */ Παράδειγμα 3 /*Δώστε τον αριθμό των ημερών της εβδομάδας για τις οποίες θέλετε να καταγράψετε τις θερμοκρασίες. Καταχωρήστε τις θερμοκρασίες σε πίνακα και υπολογίστε τη μέση θερμοκρασία, την ελάχιστη και τη μέγιστη. */ #include <stdio.h> int main(void) { int temp[31], i, min, max, avg; int days; printf("How many days in the month? "); scanf("%d", &days); for(i=0; i<days; i++) { printf("Enter noonday temperature for day %d: ", i+1); scanf("%d", &temp[i]); } /*Μέσος όρος*/ avg = 0; for(i=0; i<days; i++) avg = avg + temp[i]; printf("Average temperature: %d\n", avg/days); /*Ελάχιστο/Μέγιστο*/ min = 200; /* initialize min and max */ max = 0; for(i=0; i<days; i++) { if(min>temp[i]) min = temp[i]; if(max<temp[i]) max = temp[i]; } printf("Mini/Max temperature: %d\n %d\n", min, max); return 0; } Παράδειγμα 4: /*Γράψτε ένα πρόγραμμα σε C που να διαβάζει τον βαθμό και την τάξη από 20 μαθητές, να ελέγχει αν ο βαθμός ανήκει στο διάστημα 0-20 και αν η τάξη είναι μία από τις a, b ή c - μόλις διαβάσει τα στοιχεία ενός μαθητή, τοποθετεί τον βαθμό του σ’ έναν αντίστοιχο πίνακα ανάλογα με την τάξη που ανήκει ο μαθητής */ Δρ. Ελπινίκη Παπαγεωργίου 21 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας #include <stdio.h> main() { int bathmos, i; char taxi; int ia, ib, ic; /* μετρητές για τις τρεις τάξεις */ int a[20], b[20], c[20]; /* πίνακες βαθμών για κάθε τάξη */ ia=ib=ic=0; /* απόδοση τιμών σε πολλές μεταβλητές μαζί */ clrscr(); for (i=0; i<20; i++) { do { printf("\nΔώσε τον βαθμό του %dου μαθητή : ", i); scanf("%d", &bathmos); } while (bathmos < 0 || bathmos > 20); do { printf("\nΔώσε την τάξη του %dου μαθητή : ", i); scanf("%c", &taxi); } while (taxi != ‘a’ && taxi!=’b’ && taxi!=’c’); switch (taxi) { case ‘a’ : a[ia] = bathmos; ia++; break; case ‘b’ : b[ib] = bathmos; ib++; break; case ‘c’: c[ic] = bathmos; ic++; break; default: printf("\n Κάτι δεν πήγε καλά"); } /* end of switch */ } /* end of for */ scanf("%d", &i); } /* end of main */ Ασκήσεις για λύση 1. Να γίνει πρόγραμμα που αφού δέχεται σαν δεδομένους δύο πίνακες a και b, 10 ακεραίων ο καθένας, να υπολογίζει και αποθηκεύει σε δύο άλλους πίνακες ath και diaf το άθροισμα και την διαφορά τους αντίστοιχα. 2. Να δημιουργήσετε ένα αρχείο κειμένου με 12 πραγματικούς αριθμούς που αντιστοιχούν στις μέσες θερμοκρασίες ενός τόπου ανά μήνα. Στη συνέχεια να γίνει πρόγραμμα που αφού διαβάζει και αποθηκεύει αυτές τις θερμοκρασίες σε ένα πίνακα Δρ. Ελπινίκη Παπαγεωργίου 22 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας να υπολογίζει την μέση τιμή, την τυπική απόκλιση και την διασπορά αυτών των τιμών. 3. Να γίνει πρόγραμμα που αφού δέχεται σαν δεδομένους δύο πίνακες a και b, 10 ακεραίων ο καθένας, να τους ταξινομεί με την μέθοδο της φυσαλίδας και στη συνέχεια να τους ενοποιεί ταξινομημένα προς ένα τρίτο νέο πίνακα 20 θέσεων. Δρ. Ελπινίκη Παπαγεωργίου 23 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας 6η Εργαστηριακή Ασκηση Προγραμματισμού Ι - Γλώσσα C Σκοπός: ¾ Εξοικείωση στη χρήση συναρτήσεων (ορισμός και κλήση συναρτήσεων) ¾ Κατανόηση της αναδρομής και του τρόπου δημιουργίας αναδρομικών συναρτήσεων ΣΥΝΑΡΤΗΣΕΙΣ Συνάρτηση (function): σύνολο εντολών που έχει ομαδοποιηθεί και τους έχει αποδοθεί ένα όνομα Κλήση (calling) : η εκτέλεση των εντολών της συνάρτησης που έχει κληθεί Ορίσματα (arguments): οι παραστάσεις που επιτρέπουν στο καλούν πρόγραμμα να μεταβιβάζει πληροφορία στη συνάρτηση π.χ. printf(“Hello, World); Επιστροφή (returning): η επάνοδος στο καλούν πρόγραμμα μετά το τέλος εκτέλεσης των εντολών της συνάρτησης Επιστροφή τιμής (returning value): H επιστροφή κάποιας τιμής στο καλούν πρόγραμμα μετά το τέλος εκτέλεσης εντολών μιας συνάρτησης π.χ. n1 = GetInteger(); Δήλωση συναρτήσεων (πριν τη main) Πρωτότυπο Συνάρτησης (function prototype) επιστρεφόμενος_τύπος όνομα(όρισμα1, όρισμα2,...) επιστρεφόμενος_τύπος: ο τύπος δεδομένων της τιμής που επιστρέφει η συνάρτηση όνομα: το όνομα της συνάρτησης όρισμα: τύπος δεδομένων και όνομα μεταβλητής που μεταβιβάζεται ως όρισμα από το καλούν πρόγραμμα στη συνάρτηση void ορίζει ότι μια συνάρτηση δεν επιστρέφει κάποια τιμή ή δεν δέχεται κάποιο όρισμα π.χ. void function1(int a); π.χ. int function2(void); Ορισμός Συνάρτησης (μετά τη main) Για κάθε μη ενσωματωμένη (δική μας) συνάρτηση πρέπει να ορίσουμε το σώμα της στο πρόγραμμα (μετά την main) <τύπος> (<όνομα - συν> (<παράμετροι>); { <δηλώσεις τοπικών μεταβλητών> <προτάσεις> } return(παράσταση); παράσταση: η τιμή που επιστρέφει η συνάρτηση στο καλούν πρόγραμμα return; αν η συνάρτηση δεν επιστρέφει κάποια τιμή ο επιστρεφόμενος τύπος είναι void Δρ. Ελπινίκη Παπαγεωργίου 24 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας Κλήση Συνάρτησης (μέσα στη main) Καλείται η συνάρτηση για εκτέλεση με συγκεκριμένα ορίσματα <όνομα – συν> (<παραμ1>, <παραμ2>, …, <παραμΝ>); Τρόπος Χρήσης Συναρτήσεων main () { int a, b; f(a,b); /* καθορίζω τα δεδομένα πάνω στα οποία θα γίνει η επεξεργασία */ } void f(int x, int y) { /* στον ορισμό της συνάρτησης … αυτά τα δεδομένα έχουν … καθοριστεί γενικά … } Παράδειγμα: Συνάρτηση Υπολογισμού Δύναμης #include <stdio.h> int power(int m, int n); main() { int i, res; for (i=0; i<10; i++) { res = power (2, i); printf(“%d %d \n”, i, res); } return 0; } int power(int base, int n) { int i, p; p =1; for (i =1; i <=n; i++) p = p*base; return p; } /* να καταχωρούνται τιμές σε τρεις ακέραιες μεταβλητές και μετά να καλείται μια συνάρτηση που θα υπολογίζει τη μεγαλύτερη τιμή */ #include <stdio.h> main() { int a, b, c; int max; int maximum(); /* εδώ δηλώνουμε τις συναρτήσεις που θα χρησιμοποιήσει το πρόγραμμα - μια συνάρτηση επιστρέφει μία και μόνο μία τιμή στο όνομά της και όταν την δηλώνουμε, γράφουμε πριν από το όνομά της τον τύπο δεδομένων της, τον τύπο δεδομένων δηλ. της τιμής που επιστρέφει */ clrscr(); Δρ. Ελπινίκη Παπαγεωργίου 25 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας printf("\nΔώσε τον πρώτο αριθμό : "); scanf("%d", &a); printf("\nΔώσε τον δεύτερο αριθμό : "); scanf("%d", &b); printf("\nΔώσε τον τρίτο αριθμό : "); scanf("%d", &c); max = maximum(a, b, c); /* καλείται η συνάρτηση */ printf("\nΗ μεγαλύτερη τιμή είναι : ", max); scanf("%d", &a); } /* end of main */ /* εδώ γράφουμε τις εντολές της συνάρτησης */ int maximum(a1, b1, c1) int a1, b1, c1; /* τα a1, b1 και c1 είναι τα ορίσματα της συνάρτησης, αλλά είναι και τοπικές μεταβλητές και εδώ δηλώνεται ο τύπος δεδομένων τους */ { int max1; max1=a1; if (b1>max1) max=b1; if (c1>max1) max=c1; return max1; } /* end of sum() */ /* να καταχωρούνται τιμές σε μια ακέραια μεταβλητή και σε μια μεταβλητή χαρακτήρα και μετά να καλείται μια συνάρτηση τύπου void που θα εκτυπώνει τον χαρακτήρα τόσες φορές όσο είναι η τιμή της ακέραιας μεταβλητής εκμάθηση των συναρτήσεων τύπου void */ #include <stdio.h> main() { int a; char ch; void ektyp(); /* μια συνάρτηση τύπου void δεν επιστρέφει καμία τιμή ή επηρεάζει δύο ή περισσότερες τιμές στο κυρίως πρόγραμμα και όταν τη δηλώνουμε, γράφουμε πριν από το όνομά της τη λέξη void */ clrscr(); printf("\nΔώσε τον αριθμό : "); scanf("%d", &a); printf("\nΔώσε τον χαρακτήρα : "); scanf("%c", &ch); ektyp(a, ch); /* μια συνάρτηση τύπου void καλείται με απλή αναγραφή του ονόματός της και των ορισμάτων της */ scanf("%d", &a); } /* end of main */ void ektyp(a1, ch1) int a1; char ch1; Δρ. Ελπινίκη Παπαγεωργίου 26 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας { int i; for (i=1; i<=a1; i++) printf(ch); /* μια συνάρτηση τύπου void δεν έχει εντολή return */ } /* end of ektyp() */ Αναδρομικές Συνάρτησεις Ορισμός συνάρτησης μέσω κλήσης του εαυτού της Μία τεχνική επίλυσης προβλημάτων Π.χ. εύρεση αθροίσματος 1+2+…+n - Κλασσική λύση int sum (int n) { s=0; for (i=1; i<=n; i++) s=s+i; return s;} Αναδρομική λύση sum(n) = sum (n-1) + n int sum (int n) { if (n<=1) return n; Else return (sum(n-1)+n);} Ασκήσεις Συνάρτηση υπολογισμού του παραγοντικού ενός ακεραίου Συνάρτηση υπολογισμού αθροίσματος, διαφοράς και γινομένου δύο αριθμών. Υπολογισμός ύψωσης δύναμης ακεραίου σε μη αρνητικό ακέραιο Υπολογισμός ν-οστού όρου ακολουθίας Fibonacci 1. Να γίνει ένα πρόγραμμα το οποίο να ζητάει έναν ακέραιο από το πληκτρολόγιο, έστω το n, και να επιστρέφει στην οθόνη το n-παραγοντικό (n!). Ο υπολογισμός του παραγοντικού να γίνει σε ξεχωριστή συνάρτηση πρώτα μη αναδρομικά και κατόπιν αναδρομικά. 2. Να γίνει μια αναδρομική συνάρτηση για την ύψωση ενός ακεραίου σε έναν άλλο και να συγκριθεί με τις προηγούμενες συναρτήσεις που έκαναν τους ίδιους υπολογισμούς σε μη αναδρομική μορφή. Επίσης, να γίνει πρόγραμμα που να την χρησιμοποιεί. (δοκιμάστε και με αρνητικό εκθέτη) 3. Να γίνει μία συνάρτηση, με αναδρομική μορφή, που να υπολογίζει και να επιστρέφει την τιμή του ν-οστού όρου της ακολουθίας του Fibonacci. Κατόπιν, να γραφεί πρόγραμμα που να την χρησιμοποιεί. Δρ. Ελπινίκη Παπαγεωργίου 27 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας 7η Εργαστηριακή Ασκηση Προγραμματισμού Ι - Γλώσσα C Σκοπός: ¾ Χρήση αλφαριθμητικών (strings) ΑΛΦΑΡΙΘΜΗΤΙΚΑ 'Ενα αλφαριθμητικό (string) στη C είναι στην πραγματικότητα μία σειρά από χαρακτήρες των οποίων το τέλος υποδηλώνεται από την ύπαρξη του χαρακτήρα '\0'. Μία σταθερά τύπου string ορίζεται όπως έχουμε ήδη δει (συμβολισμός "..."), ενώ για να δηλώσουμε μία μεταβλητή τύπου string θα τη δηλώσουμε ως array χαρακτήρων. Το μέγεθος του array θα είναι το μέγιστο πλήθος χαρακτήρων που θέλουμε να χωράνε στο array συν ένα για το χαρακτήρα '\0'. 'Ετσι η δήλωση char my_string[50]; δηλώνει τη μεταβλητή my_string που χωράει 49 κανονικούς χαρακτήρες και το '\0'. Μία δήλωση μεταβλητής τύπου string μπορεί να έχει και αρχικοποίηση (με τους περιορισμούς που προαναφέρθησαν). Αυτή μπορεί να γίνει: με τον -πιο εύχρηστο- συμβολισμό char str[20] = "Hello"; Παρατηρούμε ότι δεν είναι απαραίτητο να βάλουμε το χαρακτήρα '\0', γιατί αυτό το κάνει ο compiler. 'Οπως και στους άλλους πίνακες έτσι και στα strings μπορούμε σε μία αρχικοποιημένη δήλωση να παραλείψουμε το πλήθος στοιχείων του array και ο compiler θα το συμπεράνει από την έκφραση που χρησιμοποιείται για να γίνει η αρχικοποίηση. Εκτύπωση printf (“Hello”); printf (“Ο αριθμός είναι: %s\n”, str); Εισαγωγή scanf (“%s”, str); ή scanf (“%s”, &str[0]); *διαβάζει μέχρι το πρώτο κενό *προσοχή στην υπέρβαση του μεγέθους Παράδειγμα: #include <stdio.h> #define MAX_CHARS 80 main () { char str[MAX_CHARS]; int i; printf(“Δώσε αλφαριθμητικό:”); scanf(“%s”, str); for (i = 0; i < 10; i++) printf(“%s\n”, str); } Δρ. Ελπινίκη Παπαγεωργίου 28 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας Δεδομένου ότι τα strings είναι πίνακες δεν μπορούμε να χρησιμοποιήσουμε σ' αυτά τελεστές για να ελέγξουμε την ισότητα, να εκχωρήσουμε την τιμή ενός string σε κάποιο άλλο, κ.ο.κ. Για να κάνουμε αυτές τις λειτουργίες θα πρέπει να χρησιμοποιήσουμε συναρτήσεις που παρέχονται στη βασική βιβλιοθήκη της γλώσσας C. #include <string.h>. Οι πιο συχνά χρησιμοποιούμενες από αυτές είναι: α) strcpy(char str1[], char str2[]), η οποία αντιγράφει το string str2 στο string str1. Μετά την κλήση της συνάρτησης δηλαδή το str1 θα έχει τους ίδιους χαρακτήρες με το str2. β) strncpy(char str1[], char str2[], int n), με την οποία αντιγράφουμε το πολύ n χαρακτήρες από το str2 στο str1. Η συνάρτηση αυτή χρησιμοποιείται όταν δεν είμαστε βέβαιοι ότι το str1 έχει αρκετό χώρο διαθέσιμο για να αποθηκεύσει όλους τους χαρακτήρες που περιέχονται στο str2. 'Ετσι τη συνάρτηση strncpy θα τη χρησιμοποιούσαμε σε κάποια περίπτωση όπως η πιο κάτω: char str1[20], str2[50]; ... strncpy(str1, str2, 19); Η strncpy ενδέχεται να μην προσθέσει το χαρακτήρα '\0' στο τέλος του str1 αν το str2 έχει περισσότερους χαρακτήρες από n (εξαρτάται από την υλοποίηση του compiler). Για να είναι ασφαλής έτσι μία κλήση στη strncpy θα πρέπει να ακολουθείται από την εντολή str1[n] = '\0' γ) strcat(char str1[], char str2[]) με την οποία προσθέτουμε στο τέλος του string str1 το string str2. 'Ετσι, αν το str1 έχει την τιμή "Hello " και το str2 την τιμή "there!" τότε μετά την κλήση της strcat το str1 θα έχει την τιμή "Hello there!". Το str1 θα πρέπει να έχει αρκετό χώρο για να αποθηκεύσει τους έξτρα χαρακτήρες δ) strncat(char str1[], char str2[], int n) με την οποία προσθέτουμε το πολύ n χαρακτήρες του str2 στο τέλος του str1, το οποίο πρέπει να έχει αρκετό χώρο για να αποθηκεύσει τους έξτρα χαρακτήρες. Στο νέο τέλος του str1 προστίθεται ο χαρακτήρας '\0'. ε) size_t strlen(char s[]) η οποία επιστρέφει το πλήθος των χαρακτήρων που περιέχει το string s (ο χαρακτήρας '\0' δεν υπολογίζεται). Ο τύπος size_t ορίζεται από τον C compiler με βάση ήδη υπάρχοντες τύπους. συνήθως ορίζεται ως int ή unsigned int και είναι απόλυτα ασφαλές να εκχωρήσουμε το αποτέλεσμα της strlen (ή οποιασδήποτε άλλης συνάρτησης ή τελεστή επιστρέφει τύπο size_t) σε μία μεταβλητή τύπου int ή unsigned int στ) int strcmp(char str1[], char str2[]) που επιστρέφει έναν ακέραιο μικρότερο από το μηδέν αν το str1 είναι μικρότερο από το str2, 0 αν τα strings είναι ίσα και έναν ακέραιο μεγαλύτερο από το μηδέν αν το str1 είναι μεγαλύτερο από το str2. Η σύγκριση στα strings γίνεται με λεξικογραφική σειρά, συγκρίνονται δηλαδή χαρακτήρα προς χαρακτήρα μέχρι να βρεθεί κάποιος διαφορετικός ή να φτάσουμε στο τέλος του ενός string. Αν έχει βρεθεί διαφορετικός χαρακτήρας τότε το string στο οποίο ανήκει ο μικρότερος από τους δύο χαρακτήρες είναι το μικρότερο. Αν φτάσουμε στο τέλος του ενός string, τότε αν ταυτόχρονα Δρ. Ελπινίκη Παπαγεωργίου 29 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας φτάσαμε στο τέλος του άλλου string, τα strings είναι ίσα. αν όχι, τότε το string στο τέλος του οποίου φτάσαμε είναι το μικρότερο. ζ) int strncmp(char str1[], char str2[], int n) η οποία είναι αντίστοιχη της strcmp με τη διαφορά ότι συγκρίνονται το πολύ n χαρακτήρες από τα strings η) int atoi(char s[]) η οποία μας επιστρέφει την ακέραια τιμή που αναπαριστά το string s. Αν, π.χ. το s έχει τιμή "1201" η atoi(s) θα επιστρέψει τον ακέραιο 1201. Δεν μπορούμε να επιτύχουμε το ίδιο αποτέλεσμα με το συμβολισμό (int)s. Το s μπορεί να περιέχει πρόσημο και κενά πριν και μετά από αυτό θ) long atol(char s[]) η οποία μας επιστρέφει την τύπου long τιμή που αναπαριστά το string s. Ισχύουν οι ίδιες παρατηρήσεις με την atoi. ι) double atof(char s[]) που μας επιστρέφει την τύπου doyble τιμή που περιέχεται στο string s. Το s μπορεί να περιέχει οποιαδήποτε αναπαράσταση μιας double σταθεράς. Παράδειγμα 1 #include <stdio.h> main() { char str[50]; int i=0; gets(str); while (str[i] != '\0') i++; printf("Mikos %d", i); } Παράδειγμα 2 #include <stdio.h> #include <string.h> main() { char str[256]; int n, en1, en2, i; gets(str); n = en1 = en2 = i = 0; while (str[i] != '\0') { if (str[i] >='0' && str[i] <= '9') n++; else if (str[i] >= 'a' && str[i] <= 'z') en1++; else if (str[i] >= 'A' && str[i] <= 'Z') en2++; Δρ. Ελπινίκη Παπαγεωργίου 30 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας i++; } printf("Ari8moi %d Mikra %d Kefalaia %d", n, en1, en2); } • char names[10][40]; Ένας πίνακας με10 αλφαριθμητικά, καθένα με 40 χαρακτήρες (με null). Γιά προσπέλαση καθορίζουμε μόνο τον αριστερότερο δείκτη στοιχείου. πχ. Για το 3ο αλφαριθμητικό names[2], για το 1ο printf(names[0]). Παράδειγμα 3 #include <string.h> #include <stdio.h> int main(void) { char str1[80], str2[80]; int i; printf("Enter the first string: "); printf("Enter the second string: "); gets(str1); gets(str2); printf("%s is %d chars long\n", str1, strlen(str1)); printf("%s is %d chars long\n", str2, strlen(str2)); i = strcmp(str1, str2); if(!i) printf("The strings are equal.\n"); else if(i<0) printf("%s is less than %s\n", str1, str2); else printf("%s is greater than %s\n", str1, str2); if(strlen(str1) + strlen(str2) < 80) { strcat(str1, str2); printf("%s\n", str1); } strcpy(str1, str2); printf("%s %s\n", str1, str2); } return 0; Ασκηση σε αλφαριθμητικά και πίνακες Γράψτε μια συνάρτηση stringsearch η οποία παίρνει ως παραμέτρους μια συμβολοσειρά μήκους το πολύ 20 και ένα χαρακτήρα και επιστρέφει τη θέση στη συμβολοσειρά όπου εμφανίζεται για πρώτη φορά ο χαρακτήρας (ξεκινώντας απο το 0), ή -1 αν αυτός δεν εμφανίζεται στη συμβολοσειρά. Απαγορεύεται η χρήση συναρτήσεων από το string.h Γράψτε μια συνάρτηση main η οποία: διαβάζει από το πληκτρολόγιο μια συμβολοσειρά και ένα χαρακτήρα, χρησιμοποιεί την stringsearch για να βρεί τη θέση του χαρακτήρα στη συμβολοσειρά, αν αυτός υπάρχει, εκτυπώνει τη θέση του, αν αυτός δεν υπάρχει, εκτυπώνει σχετικό μήνυμα. Δρ. Ελπινίκη Παπαγεωργίου 31 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας #include<stdio.h> #define SIZE 20 int stringsearch (char word[], char letter); int main (int argc, char *argv[]) { char word[SIZE]; char letter; int position; printf("Enter word: "); scanf("%19s", word); printf("Enter letter: "); scanf(" %c", &letter); position = stringsearch(word,letter); if ( position == -1) { printf(" '%c' does not appear in \"%s\"\n", letter, word); } else { printf(" '%c' appears at position %d in \"%s\"\n", letter, position, word); } return 0; } int stringsearch (char word[], char letter) { int i; } for (i=0; word[i] != '\0'; i++) { if (word[i] == letter) { return i; } } return -1; Ασκήσεις για λύση 1. Να γίνει μια συνάρτηση που να δέχεται μια φράση σαν όρισμα και να επιστρέφει αν είναι καρκινική ή όχι (επιστρέφοντας μη μηδενικό ακέραιο ή μηδέν αντίστοιχα). Στην συνέχεια να γραφεί πρόγραμμα που να την χρησιμοποιεί. Σας υπενθυμίζουμε ότι καρκινική φράση ή παλίνδρομο λέγεται η φράση που μπορεί να διαβαστεί και ανάποδα (π.χ. "ΑΝΝΑ", "radar", "aman a plan a canal panama", το τελευταίο αφού εξαλειφθούν οι χαρακτήρες κενού διαστήματος). 2. Να γίνει ένα πρόγραμμα το οποίο να περιέχει μια συνάρτηση η οποία θα επιστρέφει το μήκος ενός string s (μην χρησιμοποιήσετε την strlen που υπάρχει στο string.h, φτιάξτε μια δικιά σας). Επίσης, να περιέχει κι’ άλλη συνάρτηση για αντιστροφή του αλφαριθμητικού s στη θέση του. Δρ. Ελπινίκη Παπαγεωργίου 32 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας 8η Εργαστηριακή Ασκηση Προγραμματισμού Ι - Γλώσσα C Σκοπός: ¾ Κατανόηση Δεικτών ¾ Κατανόηση Δεικτών σε αλφαριθμητικά ΔΕΙΚΤΕΣ z Μεταβλητές οι οποίες περιέχουν την διεύθυνση αντικειμένων στην μνήμη z «Η p δείχνει στην q», αν η p περιέχει τη διεύθυνση της q. z τύπος *όνομα-μεταβλητής; π.χ. int *p; z Τελεστές δεικτών: *(τιμή της διεύθυνσης) , &(διεύθυνση της μεταβλητής) z Όνομα διάταξης χωρίς δείκτη στοιχείου (index) ~ ουσιαστικά παράγεται δείκτης (pointer) ο οποίος δείχνει στην αρχή της διάταξης. z Η C δεν επιτρέπει να περάσετε μια διάταξη ως όρισμα σε μία συνάρτηση, αλλά επιτρέπει το πέρασμα ενός δείκτη προς την διάταξη Π.χ. Η συνάρτηση gets() Παράδειγμα 1 #include <stdio.h> int main(void) { int *p, q; p = &q; /* get q's address */ /* assign q a value using a pointer */ *p = 199; printf("q's value is %d", q); } return 0; -------------------------------------int *p; *p = 10; /* incorrect - p is not pointing to anything */ Παράδειγμα 2 #include <stdio.h> int main(void) { char *cp, ch; int *ip, i; Δρ. Ελπινίκη Παπαγεωργίου 33 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας float *fp, f; double *dp, d; cp ip fp dp = = = = &ch; &i; &f; &d; printf("%p %p %p %p\n", cp, ip, fp, dp); return 0; } float balance[10][5]; float *p; p = (float *) balance; *(p + (3*5) + 1) -------------------------------------- Δείκτες σε αλφαριθμητικά /* Να χρησιμοποιήσετε το ακόλουθο απόσπασμα κώδικα για να εκτυπώνετε ένα αλφαριθμητικό */ char str[] = "Pointers are fun"; char *p; int i; p = str; for(i=0; p[i]; i++) printf("%c", p[i]); Παράδειγμα 3 #include <stdio.h> #include <string.h> int main(void) { char str1[] = "Pointers are fun to use"; char str2[80], *p1, *p2; /* make p point to end of str1 */ p1 = str1 + strlen(str1) - 1; p2 = str2; while(p1 >= str1) *p2++ = *p1--; /* null terminate str2 */ *p2 = '\0'; printf("%s %s", str1, str2); return 0; Δρ. Ελπινίκη Παπαγεωργίου 34 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας } Παράδειγμα 4 char *p[][2] = { "Red Delicious", "red", "Golden Delicious", "yellow", "Winesap", "red", "Gala", "reddish orange", "Cortland", "red", "Jonathan", "red", "", "" /* terminate the table with null strings */ }; #include <stdio.h> #include <string.h> int main(void) { int i; char apple[80]; printf("Enter name of apple: "); gets(apple); } for(i=0; *p[i][0]; i++) { if(!strcmp(apple, p[i][0])) printf("%s is %s\n", apple, p[i][1]); } Παράδειγμα 5 #include <stdio.h> #include <string.h> int main(void) { char *p = "stop"; char str[80]; do { printf("Enter a string: "); gets(str); } while(strcmp(p, str)); return 0; } Παράδειγμα 6 Τι κάνει το παρακάτω πρόγραμμα?? #include <stdio.h> int main(void) { char text[10][80]; int i; for(i=0; i<10; i++) { Δρ. Ελπινίκη Παπαγεωργίου 35 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας printf("%d: ", i+1); gets(text[i]); } do { printf("Enter number of string (1-10) : "); scanf("%d", &i); i--; /* adjust value to match array index */ if(i>=0 && i<10) printf("%s\n", text[i]); } while(i>=0); return 0; } Φτιάξτε προγράμματα στα οποία να αρχικοποιείτε ένα αλφαριθμητικό και να χρησιμοποιείτε τα παρακάτω κομμάτια κώδικα για κάθε περίπτωση. char *p = str; while (* str != ‘\0’) str++; printf(“%d”, str –p ); void strcpy(char *s, char *t) { int i=0; while ((s[i]=t[i])!=‘\0’) i++; } void strcpy(char *s, char *t) { while ((* s++=*t++) != ‘\0’) ; } /* να δημιουργηθεί ένας πίνακας ακεραίων 10 θέσεων, να καταχωρηθούν σ’ αυτόν τιμές με τη χρήση δεικτών και να κληθεί μια συνάρτηση τύπου void στην οποία θα περαστεί σαν όρισμα ο πίνακας και η συνάρτηση θα βρίσκει τη μεγαλύτερη τιμή και σε ποια θέση του πίνακα είναι - εκμάθηση της επεξεργασίας πίνακα με τη χρήση δεικτών και του περάσματος ενός πίνακα σαν όρισμα σε μια συνάρτηση */ #include <stdio.h> main() { int a[10]; /* Το όνομα ενός πίνακα είναι η διεύθυνση του 1ου στοιχείου του πίνακα, δηλ. ισχύει a == &a[0] και γενικά a+i == &a[i] */ int i; void maximum(); clrscr(); for (i=0; i<10; i++) { printf("\nΔώσε την %dη τιμή του πίνακα : ", i); scanf("%d", a+i); } /* end of for */ maximum(a); Δρ. Ελπινίκη Παπαγεωργίου 36 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας /* Στη συνάρτηση περνάμε το όνομα του πίνακα, δηλ. τη διεύθυνση του 1ου στοιχείου του πίνακα που είναι στην ουσία ένας δείκτης σ’ ακέραιο */ scanf("%d", &i); } /* end of main */ void maximum(a1) int *a1; /* Το a1 είναι δείκτης σ’ ακέραιο και με τη βοήθειά του έχουμε απευθείας πρόσβαση στα στοιχεία του πίνακα a[i] */ { int max, i_max, i; /* Τα max και i_max είναι τοπικές μεταβλητές */ max = *a1; i_max = 0; for (i=1; i<10; i++) { if (*(a1+i) > max) /* Το *(a1+i) = a1[i] = a[i] */ { max = *(a1+i); i_max = i; } } /* end of for */ printf("\nΗ μεγαλύτερη τιμή είναι : %d και είναι στη θέση : %d", \ max, i_max); } /* end of maximum() */ Ασκήσεις για Λύση 1. Nα γραφεί συνάρτηση με όνομα strcmp() που θα δέχεται δύο αλφαριθμητικά σαν είσοδο και θα επιστρέφει 0 αν τα δύο αλφαριθμητικά είναι ίσα, -1 αν το πρώτο αλφαριθμητικό είναι μικρότερο από το δεύτερο και 1 αν το πρώτο αλφαριθμητικό είναι μεγαλύτερο από το δεύτερο. (θα χρησιμοποιηθούν δείκτες). 2. Να φτιάξετε ένα πρόγραμμα το οποίο θα «διαβάζει» από το πληκτρολόγιο μία μεγάλη πρόταση και θα βγάζει τα εξής στοιχεία: Α) Από πόσες λέξεις αποτελείται η πρόταση; (Σημείωση: Οι λέξεις διαχωρίζονται από ένα ή και περισσότερα κενά) Β) Ποιά είναι η μικρότερη και ποια η μεγαλύτερη λέξη σε πλήθος χαρακτήρων; Σημείωση: Το πρόγραμμα να επιλυθεί αυστηρά με χρήση δεικτών (pointers). 3. Εάν έχει γίνει η δήλωση int i, j, *p, *q; Τότε ποια από τα παρακάτω είναι σωστά ποια όχι και γιατί; p = &i p = &*&i i=p q = &p q = &j i = (&)j i = *&*&j i = *p++ + *q 4. Να τροποποιηθεί η bubble sort ώστε η ανταλλαγή τιμών να γίνεται με χρήση συνάρτησης (call by reference). 5. Να γίνει πρόγραμμα με χρήση συνάρτησης που αφού δέχεται τις τιμές τριών μεταβλητών a, b, και c να μεταφέρει την τιμή του a στο b, του b στο c και του c στο a. Δρ. Ελπινίκη Παπαγεωργίου 37 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας 9η Εργαστηριακή Ασκηση Προγραμματισμού Ι - Γλώσσα C Σκοπός: ¾ Κατανόηση δομών και typedef ΔΟΜΕΣ (STRUCTURES) Δομή είναι συλλογή από μία ή περισσότερες μεταβλητές, πιθανώς διαφορετικών τύπων, που ομαδοποιούνται με ένα μόνο όνομα. Οι δομές βοηθούν στην οργάνωση περίπλοκων δεδομένων: struct <ετικέτα δομής> { <μέλη> } struct Person { char firstName[20]; char lastName[20]; char gender; int age; }; Δηλώσεις Μεταβλητών struct Person x; • Πίνακας Δομών: struct Person people[40]; • Άλλος δυνατός τρόπος: struct Person { ... } x, people[40]; Αρχικοποίηση και Χρήση • struct Person x = {“Μάκης”, “Ψ”, ‘Μ’, 40}; • struct Person people[] = {{“Μάκης”, “Ψ”, ‘Μ’, 40}, {“Κώστας”, “Α”, ‘Μ’, 50}}; • Χρήση: <όνομα δομή>.<μέλος> – x.name – x.age Δρ. Ελπινίκη Παπαγεωργίου 38 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας Εμφωλευμένες Δομές Οι δομές μπορεί να είναι αλληλένθετες, δηλαδή να φωλιάζονται η μια μέσα στην άλλη, δημιουργώντας πιο πολύπλοκες δομές: struct family { struct Person father; struct Person mother; int numofchild; struct Person children[5]; }; Παράδειγμα εμφωλευμένης δομής struct family { struct Person father; struct Person mother; int numofchild; struct Person children[5]; }; int main() { struct Person x, y, z; struct family fml; fm1.numofchild = 2; strcpy(fml.father.firstname, “Joe”); strcpy(fml.children[0].firstname, “Marry”); } Μεταβλητές τύπου δομής μπορούν να μεταβιβαστούν ως ορίσματα σε συναρτήσεις όπως επίσης και να επιστραφούν ως αποτελέσματα συναρτήσεων • Μεταβίβαση ολόκληρης δομής ή δείκτη σε αυτή struct Person inc_age (struct Person x) { x.age += 1; return x; } ... struct Person x1, x2; x2 = inc_age(x1); Παραδείγματα: /* να δημιουργηθεί μια δομή υπαλλήλου με τα εξής στοιχεία : επώνυμο, όνομα, ηλικία και μισθός και να καταχωρηθούν τιμές για 5 υπαλλήλους - να βρεθεί και να εκτυπωθεί το επώνυμο και το όνομα του υπαλλήλου που έχει Δρ. Ελπινίκη Παπαγεωργίου 39 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας τη μεγαλύτερη ηλικία καθώς και το επώνυμο και το όνομα του υπαλλήλου που έχει το μεγαλύτερο μισθό */ #include <stdio.h> struct ypalilos { char eponymo[15]; char onoma[10]; int age; long misthos; }; /* end of struct */ /* η δομή δηλώνεται πριν από τη main() και αποτελεί έναν νέο τύπο δεδομένων - μια δομή περιέχει πεδία, τα οποία μπορεί να είναι γνωστοί τύποι δεδομένων της C ή και άλλες δομές */ main() { struct ypalilos ypal; /* η μεταβλητή ypal είναι του τύπου δεδομένων ypalilos, δηλ. είναι δομή (struct) */ int i, max_age, max_misthos; char max_age_eponymo[15]; /* το επώνυμο του υπαλλήλου που έχει τη μεγαλύτερη ηλικία */ char max_age_onoma[10]; /* το όνομα του υπαλλήλου που έχει τη μεγαλύτερη ηλικία */ char max_misthos_eponymo[15]; /* το επώνυμο του υπαλλήλου που έχει το μεγαλύτερο μισθό */ char max_misthos_onoma[10]; /* το όνομα του υπαλλήλου που έχει το μεγαλύτερο μισθό */ clrscr(); max_age=0; max_misthos=0; for (i=0; i<5; i++) { printf("\nΔώσε τα στοιχεία του %dου υπαλλήλου :", i); printf("\nΕπώνυμο : "); scanf("%s", ypal.eponymo); printf("\nΌνομα : "); scanf("%s", ypal.onoma); printf("\nΗλικία : "); scanf("%d", &ypal.age); printf("\nΜισθός : "); scanf("%ld", &ypal.misthos); printf("\n"); /* αφήνει μία σειρά κενή */ /* για να αποκτήσουμε πρόσβαση στα πεδία μιας δομής, γράφουμε το όνομα της δομής, μετά τελεία (.) και μετά το όνομα του πεδίου, π.χ. ypal.eponymo - τα πεδία μιας δομής αντιμετωπίζονται όπως όλοι οι τύποι δεδομένων της C */ if (ypal.age > max_age) { Δρ. Ελπινίκη Παπαγεωργίου 40 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας max_age = ypal.age; strcpy(max_age_eponymo, ypal.eponymo); strcpy(max_age_onoma, ypal.onoma); } /* η συνάρτηση strcpy() αντιγράφει τα περιεχόμενα του δεύτερου ορίσματός της, που είναι μια συμβολοσειρά χαρακτήρων, στο πρώτο όρισμά της χρησιμοποιείται για να καταχωρούμε τιμές σε συμβολοσειρές χαρακτήρων */ if (ypal.misthos > max_misthos) { max_misthos = ypal.misthos; strcpy(max_misthos_eponymo, ypal.eponymo); strcpy(max_misthos_onoma, ypal.onoma); } } /* end of for */ printf("\nΟ %s %s έχει τη μεγαλύτερη ηλικία : %d", \ max_age_eponymo, max_age_onoma, max_age); printf("\nΟ %s %s έχει το μεγαλύτερο βαθμό : %d", \ max_misthos_eponymo, max_misthos_onoma, max_misthos); return 0; } /* end of main */ Ασκηση για την κατανόηση δομών Να γραφεί ένα πρόγραμμα, έστω το leather_store, το οποίο να ορίζει τον τύπο μιας δομής με τέσσερα μέλη: α) το όνομα ενός προϊόντος, β) τον κωδικό του, γ) την ποσότητα που βρίσκεται στην αποθήκη και δ) το κόστος του ανά τεμάχιο. Επίσης, να ορισθεί ένας γραμμικός πίνακας με Ν=500 (συμβολική σταθερά) στοιχεία, όπου το κάθε στοιχείο να είναι ίδιου τύπου με την παραπάνω δομή. Το πρόγραμμα θα πρέπει να περιέχει τις εξής συναρτήσεις: α) μια συνάρτηση για το γέμισμα του πίνακα με στοιχεία από την κονσόλα, β) μια συνάρτηση για την εκτύπωση του πίνακα υπό μορφή κατάστασης όπως στο παρακάτω παράδειγμα: Α/Α ΟΝΟΜΑ ΠΡΟΪΟΝΤΟΣ ΚΩΔΙΚΟΣ ΠΟΣΟΤΗΤΑ ΚΟΣΤΟΣ/ΤΕΜΑΧΙΟ ------------------------------------------------------------1 Τσάντα δερμάτινη 508104 86 80,75 2 Βαλίτσα δερμάτινη 705403 34 349,90 3 ……………………………… …………… ……… ………… και γ) μια συνάρτηση για την ταξινόμηση (με την μέθοδο bubble sort) του πίνακα σε αύξουσα διάταξη ως προς το πεδίο του κωδικού του προϊόντος. Το κυρίως πρόγραμμα θα καλεί τις παραπάνω συναρτήσεις με την εξής σειρά: α, β, γ, β. Δρ. Ελπινίκη Παπαγεωργίου 41 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας 10η Εργαστηριακή Ασκηση Προγραμματισμού Ι - Γλώσσα C Σκοπός: ¾ Κατανόηση δεικτών σε συναρτήσεις ¾ Κατανόηση δεικτών σε δομές ΔΕΙΚΤΕΣ ΚΑΙ ΣΥΝΑΡΤΗΣΕΙΣ Εκτός από pointers σε δεδομένα μπορούμε να ορίσουμε και pointers σε συναρτήσεις. 'Ενας pointer σε συνάρτηση ορίζεται με μία δήλωση της μορφής τύπος (*όνομα)(τ1, τ2, ..., τν) Η πιο πάνω δήλωση ορίζει τον pointer όνομα που δείχνει σε μία συνάρτηση η οποία επιστρέφει κάποιο δεδομένο τύπου τύπος και δέχεται v παραμέτρους, η πρώτη από τις οποίες είναι τύπου τ1, η δεύτερη τ2, κ.ο.κ. Η λίστα των τύπων μέσα στις παρενθέσεις μπορεί να παραλειφθεί, αλλά είναι καλό να δίνεται προκειμένου να έχουμε έλεγχο τύπων των παραμέτρων κατά την κλήση της συνάρτησης. Οι παρενθέσεις που περιβάλουν το *όνομα είναι απαραίτητες γιατί ο συμβολισμός τύπος *όνομα(τ1, τ2, ..., τν) δεν ορίζει pointer σε συνάρτηση, αλλά είναι το πρότυπο μιας συνάρτησης που ονομάζεται όνομα, επιστρέφει δεδομένο τύπου τύπος * (δηλ. pointer σε δεδομένα τύπου τύπος) και δέχεται v παραμέτρους, η πρώτη από τις οποίες είναι τύπου τ1, κ.λ.π. Για να ορίσουμε ότι κάποιος pointer σε συνάρτηση δείχνει σε κάποια συγκεκριμένη συνάρτηση χρησιμοποιούμε το συμβολισμό function_pointer = function_name; (όπου function_pointer είναι ένας pointer σε συνάρτηση και function_name το όνομα κάποιας συνάρτησης, χωρίς να ακολουθείται από παρενθέσεις. Φυσικά επιτρέπεται μία εκχώρηση της μορφής function_pointer1 = function_pointer2; Για να καλέσουμε τώρα μία συνάρτηση που δείχνεται από έναν pointer σε συνάρτηση χρησιμοποιούμε το συμβολισμό (*function_pointer)(p1, p2, ..., pν); 'Οταν χρησιμοποιούμε το συμβολισμό αυτό θα πρέπει να είμαστε απόλυτα βέβαιοι ότι ο pointer function_pointer δείχνει σε κάποια συνάρτηση, αλλιώς τα αποτελέσματα θα είναι καταστροφικά. Στο πρόγραμμα του σχήματος 23 φαίνεται η συνάρτηση sum, που δέχεται δύο παραμέτρους a και b τύπου double και έναν pointer f σε συνάρτηση που δέχεται ως όρισμα έναν double και επιστρέφει έναν double. Η συνάρτηση πιστρέφει την τιμή του ορισμένου ολοκληρώματος από a έως b της συνάρτησης που δείχνεται από τον pointer f, υπολογισμένη κατά αριθμητικό τρόπο. Η συνάρτηση main() καλεί τη συνάρτηση sum() να υπολογίσει το ορισμένο ολοκλήρωμα της exp(x) (ex) από 0 έως 2 και του λογαρίθμου με βάση 10 (log10(x)) από 10 έως 20 και εκτυπώνει τα αποτελέσματα. #include <stdio.h> #include <math.h> double sum(double a, double b, double (*f)(double)) { double step = (b - a) / 100, value = 0.0; while (a < b) { Δρ. Ελπινίκη Παπαγεωργίου 42 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας value += (*f)(a + (step / 2)) * step; a += step; } return value; } int main(int argc, char *argv[]) { printf("sum(0, 2, exp) = %g\n", sum(0.0, 2.0, exp)); printf("sum(10, 20, log10) = %g\n", sum(10, 20, log10)); return 0; } ΔΟΜΕΣ ΚΑΙ ΔΕΙΚΤΕΣ Παραδείγμα δείκτη σε δομή struct Person p; struct Person *pp; Ισχύει pp = &p; printf(“%s”, (*pp).firstName); • Οι εκφράσεις τύπου (*pp).firstName απαιτούν πάντα παρενθέσεις • Διαφορετικά είναι *pp.firstName μόνο που ο pp ΔΕΝ έχει πεδίο firstName; • Εναλλακτικά: ppÆfirstName, δηλαδή (*pp) ≡ p Æ Μεταβίβαση με δείκτη /* Για μεγάλες δομές, η μεταβίβαση με δείκτη είναι γενικά αποτελεσματικότερη επίσης χρειάζεται για πέρασμα δι’αναφοράς*/ #include <stdio.h> void initPerson(struct Person *p) { strcpy(p->firstName, “xxxxx”); strcpy(p->lastName, “yyyyy”); p.gender = ‘M’; p.age = 40; } main() { struct Person p; initPerson(&p); } Παράδειγμα 1 #include <stdio.h> #include <string.h> struct Person { char name[20]; int age; }; struct Person inc_age(struct Person x) { x.age += 1; return x; } /* Δρ. Ελπινίκη Παπαγεωργίου 43 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας struct Person inc_age(struct Person); */ main() { struct Person a = {“Yorikas”, 10}; struct Person c; c = inc_age(a); printf(“C:%d A:%d \n”, c.age, a.age); } Παράδειγμα 2 #include <stdio.h> #include <string.h> struct Person { char name[20]; int age; }; struct Person inc_age(struct Person x) { x.age += 1; return x; } struct Person inc_age_ptr(struct Person *x) { xÆage += 1; return *x; } /* struct Person inc_age (struct Person); struct Person inc_age_ptr (struct Person *); */ main() { struct Person a = {“XXX”, 10}; struct Person b = {“YYY”, 20}; struct Person c; struct Person d; c = inc_age(a); d = inc_age_ptr(&b); printf(“C:%d A:%d B:%d D:%d\n”, c.age, a.age, b.age, d.age); /* Η δομή a δεν αλλάζει τιμές */ }. Ασκήσεις για λύση 1. Να δημιουργηθεί μια δομή πελάτη με τα εξής στοιχεία : κωδικός, επώνυμο, όνομα, διεύθυνση, πόλη και υπόλοιπο και να καταχωρηθούν τιμές για 10 υπαλλήλους σ’ έναν πίνακα δομών - να εκτυπωθούν το επώνυμο και το όνομα των πελατών που έχουν υπόλοιπο μεγαλύτερο από 100000 καθώς και το συνολικό υπόλοιπο όλων των πελατών. 2. Χρησιμοποιήστε typedef για να κατασκευάστε μια απαρίθμηση (enum) με όνομα statusT η οποία αναπαριστά την διαθεσιμότητα ενός βιβλίου στη βιβλιοθήκη. Οι δυνατές τιμές είναι AVAILABLE, RESERVED, LOST και αντιστοιχούν στις ακέραιες τιμές 1, 2, και 3 αντίστοιχα. Χρησιμοποιήστε typedef για να κατασκευάστε μια δομή (struct) με όνομα bookInfoT η οποία αναπαριστά τα στοιχεία ενός βιβλίου στη βιβλιοθήκη. Περιέχει τα παρακάτω πεδία: Δρ. Ελπινίκη Παπαγεωργίου 44 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας • όνομα συγγραφέα (συμβολοσειρά μεγίστου μήκους 40) • τίτλος (συμβολοσειρά μεγίστου μήκους 40) • διαθεσιμότητα Γράψτε μια συνάρτηση με όνομα get_data η οποία παίρνει ως παράμετρο ένα πίνακα από βιβλία και τον αρχικοποιεί. Για κάθε βιβλίο διαβάζει από το πληκτρολόγιο με τη σειρά τον συγγραφέα, τον τίτλο και τη διαθεσιμότητα. Μπορείτε να υποθέσετε ότι η διαθεσιμότητα θα είναι πάντα έγκυρη τιμή. Γράψτε μια main στην οποία δηλώνετε ένα πίνακα με 5 στοιχεία τύπου bookInfoT. Καλέστε τη get_data για να αρχικοποιήσετε τον πίνακα. Δρ. Ελπινίκη Παπαγεωργίου 45 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας 11η Εργαστηριακή Ασκηση Προγραμματισμού Ι - Γλώσσα C Σκοπός: ¾ Κατανόηση των τεχνικών ταξινόμησης και αναζήτησης (Bubble sort και Binary search) ¾ Πολυδιάστατοι Πίνακες Αλγόριθμοι Ταξινόμησης /*να ταξινομηθούν κατ’ αύξουσα σειρά τα στοιχεία ενός πίνακα ακεραίων 10 θέσεων με τον αλγόριθμο Bubble-Sort - σύμφωνα με τον αλγόριθμο αυτό σαρώνουμε τα στοιχεία του πίνακα και αν ένα στοιχείο του είναι μεγαλύτερο από το επόμενό του, τότε ανταλλάσσουμε τις τιμές τους και δίνουμε την τιμή 1 σε μια μεταβλητή flag - η flag έχει την τιμή 0 κάθε φορά που μπαίνουμε στον βρόχο και αν πάρει τιμή 1 συνεχίζουμε να σαρώνουμε τον πίνακα μέχρις ότου διατηρήσει την τιμή 0 σε κάποιο πέρασμα του πίνακα - ένδειξη ότι ο πίνακας ταξινομήθηκε */ Παράδειγμα 1 #include <stdio.h> main() { int i, flag, temp, a[10]; clrscr(); /* καταχώρηση τιμών */ for (i=0; i<10; i++) { printf("\nΔώσε το %dο στοιχείο του πίνακα : ", i); scanf("%d", &a[i]); } printf("\nΟ αταξινόμητος πίνακας είναι : "); for (i=0; i<10; i++) printf("\nΤο %dο στοιχείο του πίνακα είναι : %d ", i, a[i]); do { flag = 0; for (i=0; i<9; i++) { if (a[i]>a[i+1]) { temp = a[i]; /* ανταλλαγή τιμών των */ a[i] = a[i+1]; /* a[i] και a[i+1] */ a[i+1] = temp; flag =1; } /* end of if */ } /* end of for */ } while (flag==1); printf("\nΟ ταξινομημένος πίνακας είναι : "); for (i=0; i<10; i++) printf("\nΤο %dο στοιχείο του πίνακα είναι : %d ", i, a[i]); scanf("%d", &i); } /* end of main */ Δρ. Ελπινίκη Παπαγεωργίου 46 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας /*να γίνει ο αλγόριθμος της δυαδικής αναζήτησης - δηλ. να αναζητηθεί μια τιμή σ’ έναν ταξινομημένο πίνακα 30 θέσεων - θα χρησιμοποιήσουμε δύο μεταβλητές, l1 και l2, και κάθε φορά θα συγκρίνουμε την τιμή που είναι στη μέση των δύο μεταβλητών με την αναζητούμενη τιμή - αν οι τιμές είναι ίσες, έχει βρεθεί η τιμή που ψάχνουμε, διαφορετικά ελαττώνουμε το l2 ή αυξάνουμε το l1 ανάλογα - αν τελικά διαπιστώσουμε ότι l1>l2, τότε η τιμή δεν υπάρχει */ Παράδειγμα 2 #include <stdio.h> main() { int i, l1, l2, a[30]; int value; /* η τιμή που ψάχνουμε */ int found; /* σημαία που γίνεται ίση με 1 όταν βρεθεί η τιμή */ int middle; /* η μέση τιμή του πίνακα που συγκρίνουμε */ clrscr(); /* καταχώρηση τιμών */ for (i=0; i<30; i++) { printf("\nΔώσε το %dο στοιχείο του πίνακα : ", i); scanf("%d", &a[i]); } found = 0; /* αρχικά η found είναι false (ψευδής) */ l1 = 0; /* η 1η θέση στον πίνακα */ l2 = 29; /* η τελευταία θέση στον πίνακα */ while (!found && l1<=l2) { middle = (l1 + l2) / 2; /* η μέση τιμή των l1 και l2 */ if (a[middle] == value) /* έχει βρεθεί η τιμή */ found = 1; if (a[middle] > value) /*ψάχνουμε στο 1ο μισό του πίνακα*/ l2 = middle - 1; if (a[middle] < value) /*ψάχνουμε στο 2ο μισό του πίνακα*/ l1 = middle+ 1; } /* end of while */ if (found) printf("\nΗ τιμή βρέθηκε στη θέση : %d", middle); else printf("\nΗ τιμή δεν υπάρχει στον πίνακα"); scanf("%d", &i); } /* end of main */ Πολυδιάστατοι Πίνακες Η δήλωση int a[3][3] = {{1, 2}, 3, 4, 5, 6}; ορίζει το διδιάστατο πίνακα a, με διαστάσεις 3 * 3, του οποίου κάθε στοιχείο είναι ακέραιος. Το a[0][0] θα έχει αρχική τιμή 1, το a[0][1] θα έχει αρχική τιμή 2 και το a[0][3] δεν αρχικοποιείται. Δρ. Ελπινίκη Παπαγεωργίου 47 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας Τα a[1][0], a[1][1], a[1][2] και a[2][0] θα έχουν αρχικές τιμές 3, 4, 5 και 6, αντίστοιχα, ενώ τα a[2][1] και a[2][2] δεν αρχικοποιούνται. Στις αρχικοποιημένες δηλώσεις διδιάστατων arrays μπορούμε να παραλείψουμε την πρώτη διάσταση ο compiler θα καταλάβει το μήκος της από το πλήθος και τη δομή των τιμών που χρησιμοποιούνται για αρχικοποίηση. Την πρώτη διάσταση του array μπορούμε να παραλείψουμε και όταν περνάμε ένα διδιάστατο array ως παράμετρο σε συνάρτηση. Για διδιάστατα arrays χαρακτήρων μπορούμε να χρησιμοποιήσουμε strings για αρχικοποίηση. char month_names[12][10] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; void print_month(int month) { if ((month < 1) || (month > 12)) printf("Illegal month.\n"); else printf("%s\n", month_names[month - 1]); Παράδειγμα #include <stdio.h> int main(void) { int ServerUsers[5][2] = { 1, 14, 2, 28, 3, 19, 4, 8, 5, 15 }; int server; int i; printf("Enter the server number: "); scanf("%d", &server); /* look it up in the table */ for(i=0; i<5; i++) if(server == ServerUsers[i][0]) { printf("There are %d users on server %d.\n", ServerUsers[i][1], server); break; } /* report error if not found */ if(i==5) printf("Server not listed.\n"); return 0; } Δρ. Ελπινίκη Παπαγεωργίου 48 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας Ασκήσεις για λύση 1. Γράψτε ένα πρόγραμμα που να δημιουργεί και να γεμίζει ένα μονοδιάστατο πίνακα δεκαπέντε στοιχείων με τυχαίες τιμές από 20 έως 70. Στη συνέχεια να ζητάει ένα αριθμό από το πληκτρολόγιο στο εύρος 20 - 70, και να επιστρέφει αν υπάρχει ή όχι στοιχείο στον πίνακα με αυτήν την τιμή. Το πρόγραμμα να υλοποιηθεί με τη χρήση συναρτήσεων. 2. Να συμπληρωθεί το προηγούμενο πρόγραμμα με την προσθήκη μιας συνάρτησης για την ταξινόμηση του πίνακα σε αύξουσα διάταξη. Στην συνέχεια βελτιώστε το χρησιμοποιώντας συναρτήσεις αναζήτησης που απαιτούν ταξινομημένο πίνακα. 3. Γράψτε ένα πρόγραμμα που να δημιουργεί και να γεμίζει ένα μονοδιάστατο πίνακα είκοσι στοιχείων με ακέραιες τιμές από το πληκτρολόγιο. Στη συνέχεια να ζητάει επίσης έναν ακέραιο αριθμό από το πληκτρολόγιο και να επιστρέφει αν υπάρχει ή όχι στοιχείο στον πίνακα με αυτήν την τιμή και τη θέση του στον πίνακα. Το πρόγραμμα να υλοποιηθεί με τη χρήση συναρτήσεων. Να γίνει πρόγραμμα που σε έναν δεδομένο πίνακα 3x4 να υπολογίζει το πλήθος των θετικών, μηδενικών και αρνητικών στοιχείων του. Να γίνει πρόγραμμα που σε έναν δεδομένο πίνακα 3x4 να υπολογίζει το άθροισμα των 4 στηλών του και να τους αποθηκεύει σε έναν μονοδιάστατο πίνακα. Δρ. Ελπινίκη Παπαγεωργίου 49 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας 12η Εργαστηριακή Ασκηση Προγραμματισμού Ι - Γλώσσα C Σκοπός: ¾ Κατανόηση αρχείων εισόδου/εξόδου και γραμμής εντολών ΑΡΧΕΙΑ ΣΤΗ C Ο τρόπος με τον οποίο διαβάζουμε ή γράφουμε δεδομένα σε ένα αρχείο μέσα από τη C δεν διαφέρει από τον τρόπο με τον οποίο διαβάζουμε και γράφουμε δεδομένα από την είσοδο ή στην έξοδο αντίστοιχα. Πριν όμως μπορέσουμε να διαβάσουμε ή να γράψουμε δεδομένα σε κάποιο αρχείο πρέπει να δημιουργήσουμε μία αντιστοιχία ανάμεσα σε κάποιο δεδομένο του προγράμματος και στο αρχείο αυτό. Η αντιστοιχία δημιουργείται με τη συνάρτηση fopen() η οποία παίρνει δύο παραμέτρους τύπου char *. Η πρώτη από τις παραμέτρους αντιστοιχεί στο όνομα του αρχείου, η μορφή του οποίου καθορίζεται από το λειτουργικό σύστημα στο οποίο βρισκόμαστε, και η δεύτερη καθορίζει τον τρόπο με τον οποίο θα προσπελάσουμε το αρχείο και μπορεί να έχει τις ακόλουθες τιμές: α) "r" που δηλώνει ότι θέλουμε να διαβάσουμε το αρχείο β) "w" που δηλώνει ότι θέλουμε να δημιουργήσουμε ένα νέο αρχείο στο οποίο θα γράψουμε δεδομένα. Αν το αρχείο υπάρχει, καταστρέφεται, χάνονται δηλαδή τα περιεχόμενά του γ) "a" που δηλώνει ότι θέλουμε να προσθέσουμε δεδομένα στο αρχείο. Αν το αρχείο υπάρχει τα περιεχόμενά του δεν καταστρέφονται και τα νέα δεδομένα προστίθενται στο τέλος του, ενώ αν δεν υπάρχει δημιουργείται δ) "r+" που ανοίγει το αρχείο όπως και το "r" αλλά μας επιτρέπει και να γράψουμε στο αρχείο, με αποτέλεσμα να αλλάζουμε τα δεδομένα που υπήρχαν εκεί, αν η εγγραφή γίνεται στο μέσον του αρχείου ή να προστίθενται στο αρχείο, αν η εγγραφή γίνεται στο τέλος του αρχείου ε) "w+" που ανοίγει το αρχείο όπως και το "w", αλλά μας επιτρέπει επίσης να διαβάσουμε το αρχείο στ) "a+" που ανοίγει το αρχείο όπως και το "a", αλλά μας επιτρέπει επίσης να διαβάσουμε το αρχείο. Οι εγγραφές δεδομένων γίνονται πάντα στο τέλος του αρχείου Το πρόγραμμά μας έχει το δικαίωμα να κλείσει τα αρχεία αυτά (χρησιμοποιώντας την fclose()), αλλά δεν μπορεί να τα ανοίξει χρησιμοποιώντας το συμβολισμό stdin = fopen("datafile", "r"); Αν επιθυμούμε να αλλάξουμε τη σύνδεση ενός τέτοιου αρχείου, συνδέοντάς το με κάποιο συγκεκριμένο αρχείο, τότε θα χρησιμοποιήσουμε τη συνάρτηση freopen() της οποίας το πρότυπο είναι: FILE *freopen(char *filename, char *mode, FILE *stream); Η συνάρτηση αυτή κλείνει το αρχείο stream και κατόπιν ανοίγει το αρχείο filename με τρόπο προσπέλασης που καθορίζεται από το mode και συσχετίζει το ανοικτό αρχείο με το stream. Η συνάρτηση επιστρέφει NULL αν η λειτουργία δεν επέτυχε. Αν θέλουμε λοιπόν οι συναρτήσεις εισόδου να παίρνουν την είσοδό τους από το αρχείο "myfile.dat" θα πρέπει να καλέσουμε την freopen() με freopen("myfile.dat", "r", stdin); Δρ. Ελπινίκη Παπαγεωργίου 50 Τμήμα Πληροφορικής & τεχνολογίας Υπολογιστών ΤΕΙ Λαμίας Η συνάρτηση fopen() επιστρέφει ένα αντικείμενο τύπου FILE * (ο τύπος αυτός είναι ορισμένος στο αρχείο stdio.h), το οποίο μπορούμε να το περάσουμε στη συνέχεια ως παράμετρο σε συναρτήσεις για να γράψουμε ή να διαβάσουμε δεδομένα από το αρχείο αυτό. Αν το άνοιγμα του αρχείου ήταν αδύνατο (π.χ. αν θέλαμε να ανοίξουμε για ανάγνωση ένα αρχείο που δεν υπήρχε) τότε η fopen() επιστρέφει τη σταθερά NULL. Για να ανοίξουμε έτσι το αρχείο "data" για να διαβάσουμε δεδομένα θα χρησιμοποιήσουμε τον κώδικα: ... FILE *infile; infile = fopen("data", "r"); if (infile == NULL) { printf("Error opening file data for input\n"); exit(2); } (η συνάρτηση exit είναι ορισμένη στο αρχείο stdlib.h και τερματίζει το πρόγραμμα επιστρέφοντας στο λειτουργικό σύστημα τον ακέραιο που δέχεται ως παράμετρο). Παράδειγμα #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { FILE *fp; int i; if ((fp = fopen("datafile", "w")) == NULL) { fprintf(stderr, "Can't open datafile for output\n"); exit(2); for (i = 1; i <= 20; i++) fprintf(fp, "%11d\t%11d\n", i, 2 * i); fputc('\n', fp); fclose(fp); return 0; } Δρ. Ελπινίκη Παπαγεωργίου 51
© Copyright 2024 Paperzz