ΤΜΗΜΑ ΕΦΑΡΜΟΣΜΕΝΗΣ ΠΛΗΡΟΦΟΡΙΚΗΣ Διαδικαστικός Προγραμματισμός Α Εξάμηνο Μάθημα 11 ο : Αρχεία κειμένου
Στόχοι μαθήματος Να κατανοήσετε την έννοια του αρχείου κειμένου και τον τρόπο με τον οποίο αυτά τα αρχεία επιτρέπουν τη μόνιμη αποθήκευση πληροφοριών. Να μπορείτε να ανοίγετε και να κλείνετε αρχεία χρησιμοποιώντας τις συναρτήσεις fopen και fclose αντίστοιχα. Να μάθετε να επεξεργάζεστε αρχεία σε κατάσταση χαρακτήρα χρησιμοποιώντας τις συναρτήσεις getc και putc. Να κατανοήσετε την έννοια της μορφοποιημένης εισόδου/εξόδου σε αρχεία. 2
Η χρησιμότητα των αρχείων Κάθε φορά που θέλετε να αποθηκεύσετε πληροφορίες στον υπολογιστή για χρονικό διάστημα μεγαλύτερο από το χρόνο εκτέλεσης ενός προγράμματος, μπορείτε να χρησιμοποιείτε ένα αρχείο (file). Ένα αρχείο είναι μια ομαδοποίηση δεδομένων σε ένα λογικά συνεκτικό σύνολο και η αποθήκευση του σε ένα μέσο μόνιμης αποθήκευσης. 3
Αρχεία κειμένου Όταν αποθηκεύουμε σε ένα αρχείο δεδομένα προκειμένου να χρησιμοποιηθούν από κάποιο πρόγραμμα, αυτό το αρχείο αποτελείται συνήθως από κείμενο και γι αυτόν το λόγο ονομάζεται αρχείο κειμένου (text file). Αν υποθέσουμε ότι έχουμε ένα αρχείο, έστω hamlet.txt: To be or not to be: that is the question. Whether tis nobler in the mind to suffer αυτό θα αναπαρασταθεί στο εσωτερικό του υπολογιστή ως μια μονοδιάστατη ακολουθία χαρακτήρων To be or not to be: that is the question.\nwhether tis nobler in the mind to suffer \n Κάθε αρχείο κειμένου τελειώνει με έναν ειδικό χαρακτήρα τέλους αρχείου που υποδηλώνει ότι δεν υπάρχουν άλλοι χαρακτήρες μετά από εκείνο το σημείο. 4
Χρήση αρχείων στη C Για να χρησιμοποιήσετε κάποιο αρχείο δεδομένων σε ένα πρόγραμμα C, πρέπει να κάνετε τα εξής: 1. Να δηλώσετε μια μεταβλητή τύπου FILE * (δείκτης αρχείου). 2. Να συσχετίσετε τη μεταβλητή με ένα πραγματικό αρχείο καλώντας την fopen, λειτουργία γνωστή ως άνοιγμα (opening) του αρχείου. 3. Να καλέσετε τις κατάλληλες συναρτήσεις της βιβλιοθήκης stdio.h για να εκτελέσετε τις λειτουργίες εισόδου/εξόδου, προκειμένου να διαβάσετε από ή να γράψετε σε αρχεία. Στην περίπτωση ενός αρχείου εισόδου οι συναρτήσεις θα μεταφέρουν δεδομένα από το αρχείο στο πρόγραμμα Στην περίπτωση ενός αρχείου εξόδου οι συναρτήσεις θα μεταφέρουν δεδομένα από το πρόγραμμα στο αρχείο 4. Να υποδείξετε ότι οι λειτουργίες ολοκληρώθηκαν καλώντας την fclose, λειτουργία γνωστή ως κλείσιμο (closing) του αρχείου. 5
Δήλωση μιας μεταβλητής FILE * (1) FILE: τύπος που ορίζεται στην πρότυπη βιβλιοθήκη εισόδου/εξόδου και χρησιμοποιείται για την αποθήκευση των πληροφοριών που απαιτούνται από το σύστημα για τη διαχείριση της δραστηριότητας των αρχείων. Για να μπορέσετε να διαχειριστείτε ένα αρχείο πρέπει να δηλώσετε στη C ένα δείκτη προς μια δομή FILE ως εξής: FILE *infile; FILE *mydata; Όπως ήδη γνωρίζουμε ένας δείκτης (pointer) είναι ένα στοιχείο δεδομένων του οποίου η τιμή είναι η διεύθυνση που έχει στη μνήμη κάποια άλλη τιμή. Έτσι, στην περίπτωση μας η μεταβλητή infile «δείχνει» προς τη δομή του συστήματος αρχείων. 6
Δήλωση μιας μεταβλητής FILE * (2) Αν σε ένα πρόγραμμα χρειαζόμαστε περισσότερα από ένα αρχεία τότε πρέπει να δηλώσουμε ισάριθμες μεταβλητές τύπου FILE * ως εξής: FILE *infile, *outfile, *mydata; Στη συνέχεια, στις κλήσεις των συναρτήσεων για το διάβασμα δεδομένων από ένα αρχείο ή την εγγραφή δεδομένων σε ένα αρχείο θα χρησιμοποιούμε ως ορίσματα τις παραπάνω μεταβλητές τύπου FILE *. 7
Άνοιγμα αρχείου (1) Όταν δηλώνετε μια μεταβλητή τύπου FILE * για πρώτη φορά, αυτή δεν συσχετίζεται με κάποιο πραγματικό αρχείο. Για να γίνει αυτός ο συσχετισμός πρέπει να καλέσετε τη συνάρτηση fopen: μεταβλητή δείκτη FILE* = fopen(όνομα αρχείου, τρόπος); Ο τρόπος μεταφοράς δεδομένων είναι ένας από τους εξής: r ανοίγει το αρχείο για ανάγνωση (reading). Το αρχείο θα πρέπει να υπάρχει ήδη και η μεταβλητή δείκτη που θα επιστραφεί μπορεί να χρησιμοποιηθεί μόνο σε λειτουργίες εισόδου. w ανοίγει το αρχείο για εγγραφή (writing). Αν το αρχείο υπάρχει τότε σβήνονται τα περιεχόμενα του, διαφορετικά δημιουργείται. Η μεταβλητή δείκτη που θα επιστραφεί μπορεί να χρησιμοποιηθεί μόνο σε λειτουργίες εξόδου. a ανοίγει το αρχείο για προσάρτηση (appending). Ίδιο με το w, αλλά εάν το αρχείο υπάρχει, τα νέα δεδομένα γράφονται στο τέλος των ήδη υπαρχόντων. 8
Άνοιγμα αρχείου (2) Παράδειγμα: Άνοιγμα του αρχείου juliet.txt για είσοδο δεδομένων (διάβασμα από το αρχείο στο πρόγραμμα) και συσχέτιση με τη μεταβλητή infile: infile = fopen ( juliet.txt, r ); Αν το αρχείο εισόδου λείπει ή ανιχνευθούν άλλα λάθη η κλήση της fopen θα επιστρέψει το δείκτη NULL. - Άρα καλό είναι να γίνεται πάντα έλεγχος αν όλα έχουν καλώς. while (TRUE) { printf ( Input file name: ); gets(filename); infile = fopen (filename, r ); if (infile!= NULL) break; printf ( Cannot open file %s. Try again.\n, filename); } 9
Εκτέλεση λειτουργιών εισόδου/εξόδου (1) Αφού ανοίξουμε ένα αρχείο, το επόμενο βήμα είναι να διαβάσουμε ή να γράψουμε τα δεδομένα. Αυτό μπορεί να γίνει επιλέγοντας κάποια από τις παρακάτω στρατηγικές, ανάλογα με την εφαρμογή: Διάβασμα/εγγραφή ανά χαρακτήρα: χρησιμοποιούνται οι συναρτήσεις getc() και putc() αντίστοιχα. δες το showfile.c Διάβασμα/εγγραφή ανά γραμμή: χρησιμοποιούνται οι συναρτήσεις fgets() και fputs (διασύνδεση stdio.h) αντίστοιχα, ή η ReadLine() (αν η διαχείριση των αλφαριθμητικών γίνει με τη βιβλιοθήκη strlib.h ). δες το linecopy.c Μορφοποιημένη είσοδος και έξοδος: χρησιμοποιούνται οι συναρτήσεις fscanf() και fprintf() αντίστοιχα. 10
Κλείσιμο αρχείων Το κλείσιμο ενός αρχείου γίνεται με την κλήση της συνάρτησης fclose στην οποία μεταβιβάζεται ο κατάλληλος δείκτης προς αρχείο: fclose (infile); fclose (outfile); Είναι καλό να κλείνετε τα αρχεία με τη συνάρτηση fclose γιατί έτσι: οι αναγνώστες ενός προγράμματος μπορούν εύκολα να καταλαβαίνουν πότε ένα αρχείο είναι σε χρήση και πότε δεν χρειάζεται πλέον. είναι ευκολότερο να ενσωματώνουμε τον κώδικα μας σε μεγαλύτερα προγράμματα που ενδέχεται να διαχειρίζονται δικά τους αρχεία. 11
Καθιερωμένα αρχεία Στη πρότυπη βιβλιοθήκη εισόδου/εξόδου stdio.h ορίζονται 3 ειδικά προσδιοριστικά τα stdin, stdout, stderr τα οποία λειτουργούν ως σταθερές τύπου FILE * και είναι διαθέσιμα σ όλα τα προγράμματα. Αυτές οι σταθερές είναι γνωστές ως καθιερωμένα αρχεία (standard files). Η σταθερά stdin, υποδεικνύει το καθιερωμένο αρχείο για την είσοδο δεδομένων από το χρήστη, αναπαριστά τη συσκευή απ όπου ο χρήστης εισάγει δεδομένα, που είναι το πληκτρολόγιο Η σταθερά stdout, υποδεικνύει το καθιερωμένο αρχείο για την έξοδο δεδομένων και αναπαριστά τη συσκευή στην οποία γράφονται τα δεδομένα εξόδου, που είναι η οθόνη Η σταθερά stderr αναπαριστά το καθιερωμένο αρχείο σφαλμάτων, που είναι η οθόνη. Σε ορισμένα συστήματα είναι δυνατή η αλλαγή αυτών των καθιερωμένων συσχετίσεων έτσι η καθιερωμένη είσοδος να προέρχεται από αρχείο ή καθιερωμένη έξοδος να κατευθύνεται σε αρχείο ή άλλη συσκευή. 12
Είσοδος χαρακτήρων (1) Η απλούστερη προσέγγιση για την επεξεργασία των αρχείων είναι να διατρέχετε τα αρχεία χαρακτήρα προς χαρακτήρα. Χρησιμοποιείτε τη συνάρτηση getc ή την ισοδύναμη fgetc int getc(file *infile); Η οποία διαβάζει και επιστρέφει τον επόμενο χαρακτήρα του αρχείου infile. Η τιμή που επιστρέφει είναι ένας ακέραιος (και όχι ο χαρακτήρας) έτσι ώστε ο τύπος του αποτελέσματος να μπορεί να περιλαμβάνει και τη ειδική τιμή EOF που σηματοδοτεί το τέλος του αρχείου. Η EOF έχει συνήθως τη τιμή -1. Η συνάρτηση int getchar() λειτουργεί με τον ίδιο τρόπο με τη διαφορά ότι διαβάζει πάντα τα δεδομένα εισόδου από τη καθιερωμένη είσοδο το πληκτρολόγιο. 13
Είσοδος χαρακτήρων (2) #define MaxFileName 40 main() { FILE *mydata; char name[maxfilename]; int ch; printf("this program shows the content of a file.\n"); while (TRUE) { printf("please insert file name: "); gets(name); mydata = fopen(name,"r"); Άνοιγμα Αρχείου if (mydata!= NULL) break; printf("%s does not exist.\n",name); } } while (TRUE){ ch = getc(mydata); if (ch == EOF) break; printf("%c",ch); } fclose(mydata); Επεξεργασία Κλείσιμο Αρχείου 14
Έξοδος χαρακτήρων (1) Για να γράψετε ένα μεμονωμένο χαρακτήρα σε αρχείο χρησιμοποιείτε τη συνάρτηση int putc(int ch, FILE *outfile); η οποία γράφει το χαρακτήρα ch στο αρχείο εξόδου outfile Αν η εγγραφή είναι επιτυχής, τότε επιστρέφει το χαρακτήρα που γράφτηκε, αλλιώς EOF. Αντίστοιχη είναι η συνάρτηση int putchar() η οποία γράφει το χαρακτήρα στη καθιερωμένη έξοδο οθόνη Παράδειγμα που ακολουθεί: copyfile.c Διαβάζει από ένα αρχείο δεδομένα χαρακτήρα-χαρακτήρα και γράφει σε άλλο αρχείο χαρακτήρα-χαρακτήρα. 15
Έξοδος χαρακτήρων (2) Έστω ότι θέλετε να αντιγράψετε χαρακτήρα-χααρακτήρα τα περιεχόμενα: ενός αρχείου infile, το οποίο έχετε ήδη ανοίξει επιτυχώς ("r"), στο αρχείο outfile, το οποίο έχετε ήδη ανοίξει για εγγραφή ("w").... σε μια συνάρτηση CopyFile void CopyFile(FILE *infile, FILE *outfile) { int ch; } while (TRUE) { ch = getc(infile); if (ch == EOF) break; putc (ch, outfile); } Εναλλακτικά while ((ch = getc(infile))!= EOF) { putc(ch, outfile); } 16
Συνάρτηση για άνοιγμα αρχείου Επειδή έχουμε να "ανοίξουμε" δύο αρχεία, καλό είναι να δημιουργήσουμε μια συνάρτηση για το "επιτυχές" άνοιγμα. Επιστρέφει ένα δείκτη σε αρχείο Παράμετροι: Μήνυμα προς χρήστη (prompt) και τρόπος μεταφοράς... σε μια συνάρτηση OpenUserFile FILE *OpenUserFile(char *prompt, char *mode) { char filename[30]; FILE *result; Διαβάζει το πραγματικό όνομα του αρχείου στο τοπικό σύστημα (πχ δίσκο ΗΥ) (filename) } while (TRUE) { printf("%s", prompt); Ανοίγει το αρχείο συσχετίζοντας το gets(filename); πραγματικό όνομα filename με τη result = fopen(filename, mode); μεταβλητή result τύπου FILE if (result!= NULL) break; printf("can't open the file \"%s\"\n", filename); } return (result); 17
Είσοδος και έξοδος χαρακτήρων (2) /* Αντιγραφή ενός αρχείου σε ένα άλλο. */ #include <stdio.h> #include "genlib.h" /* function prototypes */ void CopyFile(FILE *infile, FILE *outfile); FILE *OpenUserFile(char *prompt, char *mode); /* Main program */ main() { FILE *infile, *outfile; printf("this program copies one file to another.\n"); infile = OpenUserFile("Old file: ", "r"); outfile = OpenUserFile("New file: ", "w"); CopyFile(infile, outfile); fclose(infile); fclose(outfile); } 18
Είσοδος και έξοδος γραμμών κειμένου Επειδή τα αρχεία υποδιαιρούνται συνήθως σε γραμμές, βολεύει να διαβάζετε μια ολόκληρη γραμμή δεδομένων τη φορά. Η συνάρτηση char *fgets (char buffer[], int bufsize, FILE *infile) ή char *fgets (char *buffer, int bufsize, FILE *infile) διαβάζει την επόμενη γραμμή δεδομένων του αρχείου και την αποθηκεύει στον πινάκα χαρακτήρων buffer[] (ή στον πινάκα χαρακτήρων στο οποίο δείχνει ο δείκτης buffer). Σταματά το διάβασμα όταν διαβάσει bufsize-1 χαρακτήρες, ή το χαρακτήρα αλλαγής γραμμής, ή το χαρακτήρα τέλους του αρχείου, οποιοδήποτε συμβεί πρώτο. Προσθέτει το χαρακτήρα τερματισμού ( \0 ) στους χαρακτήρες που διαβάστηκαν. Αν η συνάρτηση εκτελεστεί επιτυχώς τότε επιστρέφει ως τιμή ένα δείκτη στον πίνακα χαρακτήρων buffer αλλιώς τη τιμή NULL. 19
Είσοδος και έξοδος γραμμών κειμένου Η αντίστοιχη συνάρτηση για την έξοδο δεδομένων είναι η int fputs(char *buffer, FILE *outfile) αντιγράφει το αλφαριθμητικό buffer στο αρχείο εξόδου outfile μέχρι να εμφανισθεί ο χαρακτήρας τέλους του αλφαριθμητικού buffer. Επιστρέφει μια μη αρνητική τιμή όταν όλα έχουν πάει καλά. Συνάρτηση CopyFile με την χρήση συναρτήσεων fgets, fputs. #define MaxLine 80 void CopyFile(FILE *infile, FILE *outfile) { char buffer[maxline]; while (fgets(buffer, MaxLine, infile)!= NULL) { fputs(buffer, outfile); } } 20
Μορφοποιημένη είσοδος και έξοδος (1) Η συνάρτηση printf έχει τρεις διαφορετικές μορφές: printf (αλφαριθμητικό ελέγχου,...); στέλνει τα δεδομένα εξόδου στην καθιερωμένη έξοδο (οθόνη ΗΥ) fprintf (ρεύμα εξόδου, αλφαριθμητικό ελέγχου,...); στέλνει τα δεδομένα εξόδου σε αρχείο sprintf (πίνακας χαρακτήρων, αλφαριθμητικό ελέγχου,...); στέλνει τα δεδομένα εξόδου σε πίνακα 21
Μορφοποιημένη είσοδος και έξοδος (2) Η συνάρτηση scanf έχει τρεις διαφορετικές μορφές: int scanf(αλφαριθμητικό ελέγχου,...); Διαβάζει τα δεδομένα εισόδου από την καθιερωμένη είσοδο int fscanf(ρεύμα εισόδου, αλφαριθμητικό ελέγχου,...); Διαβάζει τα δεδομένα εισόδου από αρχείο (το δείκτη FILE που καθορίζεται με την παράμετρο ρεύμα εισόδου) sscanf(αλφαριθμητικό χαρακτήρων, αλφαριθμητικό ελέγχου,...); Διαβάζει τα δεδομένα εισόδου από το καθορισμένο αλφαριθμητικό χαρακτήρων Επειδή η scanf πρέπει να επιστρέφει πληροφορίες σ αυτόν που την καλεί γι αυτό τα ορίσματα που ακολουθούν το αλφαριθμητικό έλεγχου πρέπει να καθορίζονται με κλήση κατ αναφορά (δείκτες) (εκτός από πίνακες και πίνακες χαρακτήρων που αποτελούν δείκτες από μόνα τους). 22
Μορφοποιημένη είσοδος και έξοδος (3) Προδιαγραφές μετατροπής της συνάρτησης scanf/fscanf %d διαβάζει ένα ακέραιο %f, %e, %g, διαβάζει έναν αριθμό κινητής υποδιαστολής (τύπου float) %lf διαβάζει έναν αριθμό κινητής υποδιαστολής (τύπου double) %c διαβάζει τον επόμενο χαρακτήρα. %s διαβάζει ένα αλφαριθμητικό %[...], διαβάζει όσους χαρακτήρες συναντήσει ΚΑΙ βρίσκονται στη λίστα. -πχ, %[abc] %[^...], διαβάζει όσους χαρακτήρες συναντήσει μέχρι να βρει κάποιον που βρίσκεται στη λίστα. %% δεν κάνει καμιά μετατροπή ο επόμενος χαρακτήρας πρέπει να είναι σύμβολο ποσοστού Παράδειγμα int num; char c; char name [30]; float x; scanf("%d %c %s %f",&num,&c,name,&x); 23
Παράδειγμα Έστω το αρχείο δεδομένων elements.dat που έχει τη παρακάτω μορφή: Hydrogen, H, 1, 1.008 Helium, He, 2, 4.003 Lithium, Li, 3, 6.939 Beryllium, Be, 4, 9.012 Boron, B, 5, 10.811 Carbon, C, 6, 12.011 Nitrogenm, N, 7, 14.007 Oxygen, O, 8, 15.999 Fluorine, F, 9, 18.998 Neon, Ne, 10, 20.183 Μορφή CSV (Comma Seperated Values) Το πρόγραμμα elements.c διαβάζει από το αρχείο και τυπώνει τα στοιχεία στην οθόνη. 24
Παράδειγμα Έστω το αρχείο αρχείο δεδομένων elements.dat που έχει τη παρακάτω μορφή: Hydrogen, H, 1, 1.008 Helium, He, 2, 4.003 Αλφαριθμητικό (max 15) Αλφαριθμητικό (max 2) Ακέραιος Πραγματικός \n Πως θα διαβάσω μέχρι 15 χαρακτήρες το πολύ ή μέχρι να βρω το ","? Πως θα διαβάσω το ","?, κλπ. "%15[^,], %2[^,], %d, %lf%c" 25
Παράδειγμα (1) //filename elements.c #include <stdio.h> #include "genlib.h" #include "simpio.h" #define ElementsFile "elements.dat" #define MaxElementName 15 #define MaxSymbolName 2 main() { FILE *infile; char elementname[maxelementname+1]; char elementsymbol[maxsymbolname+1]; char namebuf[maxelementname+maxsymbolname+4]; int atomicnumber; double atomicweight; char termch; int nscan; 26
Παράδειγμα (2) infile = fopen(elementsfile, "r"); if (infile == NULL) Error("Can't open %s", ElementsFile); printf(" Element (symbol) Atomic Weight\n"); printf("--------------------------------------\n"); } } while (TRUE) { nscan = fscanf(infile, "%15[^,], %2[^,], %d, %lf%c", elementname, elementsymbol, &atomicnumber, &atomicweight, &termch); if (nscan == EOF) break; if (nscan!= 5 termch!= '\n') { Error("Improper file format"); } Συνδυάζουμε τα 2 αλφαριθμητικά (elementname, elementsymbol) σε 1(namebuf) με την sprintf sprintf(namebuf, "%s (%s)", elementname, elementsymbol); printf("%3d. %-20s %8.3f\n", atomicnumber, namebuf, atomicweight); 27
Παράδειγμα (2) nscan = fscanf(infile, "%15[^,], %2[^,], %d, %lf%c", elementname, elementsymbol, &atomicnumber, &atomicweight, &termch); Στην fscanf το "%15[^,], %2[^,], %d, %lf%c", είναι αλφαριθμητικό ελέγχου που επιτρέπει τη σωστή ανάγνωση μιας γραμμής δεδομένων από το αρχείο. Η μεταβλητή elementname θα δεχθεί χαρακτήρες μέχρι να βρεθεί το πρώτο κόμμα (,) και μέχρι το πολύ 15 χαρακτήρες Στη συνέχεια στη μεταβλητή elementsymbol θα αποθηκευθούν οι επόμενοι χαρακτήρες μέχρι να βρεθεί το κόμμα (,) και μέχρι το πολύ 2 χαρακτήρες Στη συνέχεια στη μεταβλητή atomicnumber θα αποθηκευθεί ο επόμενος ακέραιος αριθμός Στη συνέχεια στη μεταβλητή atomicweight θα αποθηκευθεί ο επόμενος πραγματικός αριθμός (double) Στη συνέχεια στη μεταβλητή termch αποθηκεύεται o χαρακτήρας τερματισμού της γραμμής Το αρχείο δεδομένων elemants.dat που συσχετίζεται με τη μεταβλητή inflie τύπου FILE έχει την εξής μορφή Hydrogen, H, 1, 1.008 Helium, He, 2, 4.003 Lithium, Li, 3, 6.939. 28
Παράδειγμα (2) Συνδυάζουμε τα 2 αλφαριθμητικά (elementname, elementsymbol) σε ένα αλφαριθμητικό (namebuf) με την sprintf sprintf(namebuf, "%s (%s)", elementname, elementsymbol); Και μετά χρησιμοποιούμε τις καθιερωμένες δυνατότητες ορισμού πλάτους πεδίου της printf για να παράγουμε τη σωστή έξοδο, δηλαδή το όνομα κάθε στοιχείου και το αντίστοιχο χημικό σύμβολο πρέπει να εμφανίζονται μαζί σε ένα πεδίο και η στήλη με τα ατομικά βάρη να ευθυγραμμίζονται σωστά. Οπότε δημιουργούμε 1 στήλη (για το όνομα κάθε στοιχείου και το αντίστοιχο χημικό σύμβολο) 20 χαρακτήρων printf("%3d. %-20s %8.3f\n", atomicnumber, namebuf, atomicweight); 29
Διορθώσεις στο βιβλίο σχετικά με τα αρχεία Αφορά στο βιβλίο του Roberts : Η τέχνη και επιστήμη της C Στη σελίδα 620 αντικαταστήστε το λανθασμένη πρωτότυπο της συνάρτησης fputs από void fputs(string str, FILE *outfile); σε int fputs(string str, FILE *outfile); Στη σελίδα 769 αντικαταστήστε το λανθασμένη πρώτυπο της συνάρτησης putc από void putc(char ch, FILE *outfile); σε int putc(int ch, FILE *outfile); Σ όλο το κεφάλαιο 15 αλλά και στο παράρτημα Α.9 (σελίδες 759-762 βιβλιοθήκη stdio.h) αντικαταστήστε στα πρωτότυπα των συναρτήσεων για τη διαχείριση αρχείων, το τύπο string (δεν υποστηρίζεται από την ANSI C) με το τύπο char* ή char[]. 30