Εισαγωγή στους Δείκτες (Pointers)

Σχετικά έγγραφα
Η Γλώσσα Προγραμματισμού C (Μέρος 3 - Συναρτήσεις, Πίνακες και Δείκτες) Εισαγωγή στις Συναρτήσεις

Εισαγωγή στις Συναρτήσεις

Προγραμματισμός Η/Υ (ΤΛ2007 )

Η γλώσσα προγραμματισμού C

3ο σετ σημειώσεων - Πίνακες, συμβολοσειρές, συναρτήσεις

Προγραμματισμός Η/Υ (ΤΛ2007 )

Η γλώσσα προγραμματισμού C

ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ Η/Υ Ακαδημαϊκό έτος ΤΕΤΡΑΔΙΟ ΕΡΓΑΣΤΗΡΙΟΥ #4

Η γλώσσα προγραμματισμού C

Διαδικασιακός Προγραμματισμός

Εισαγωγή στον Προγραμματισμό

Προγραμματισμός Η/Υ (ΤΛ2007 )

Διδάσκων: Κωνσταντίνος Κώστα Διαφάνειες: Δημήτρης Ζεϊναλιπούρ

Δομημένος Προγραμματισμός

Προγραμματισμός Ι. Χαρακτήρες. Πανεπιστήμιο Πελοποννήσου Τμήμα Πληροφορικής & Τηλεπικοινωνιών

Δομημένος Προγραμματισμός. Τμήμα Επιχειρηματικού Σχεδιασμού και Πληροφοριακών Συστημάτων

Κεφάλαιο Αλφαριθμητικές Σειρές Χαρακτήρων (Strings) (Διάλεξη 20) 1) Strings στη C

Η γλώσσα προγραμματισμού C

Διάλεξη 2: Επανάληψη Προγραμματισμού Συμβολοσειρές (strings) Διδάσκων: Παναγιώτης Ανδρέου

Στόχοι και αντικείμενο ενότητας. Τύπος πίνακα. Τύπος πίνακα (συν.) #6. Πίνακες και Δείκτες

6. ΠΙΝΑΚΕΣ & ΑΛΦΑΡΙΘΜΗΤΙΚΑ

Η πρώτη παράμετρος είναι ένα αλφαριθμητικό μορφοποίησης

Διάλεξη 3η: Τύποι Μεταβλητών, Τελεστές, Είσοδος/Έξοδος

Δομημένος Προγραμματισμός (ΤΛ1006)

Διαδικασιακός Προγραμματισμός

Δομημένος Προγραμματισμός (ΤΛ1006)

Τμήμα Πληροφορικής & Επικοινωνιών Δρ. Θεόδωρος Γ. Λάντζος

Εισαγωγή στην C. Μορφή Προγράµµατος σε γλώσσα C

Προγραμματισμός Ι. Συναρτήσεις. Πανεπιστήμιο Πελοποννήσου Τμήμα Πληροφορικής & Τηλεπικοινωνιών

Κεφάλαιο 8.7. Πολυδιάστατοι Πίνακες (Διάλεξη 19)

ΑΣΚΗΣΗ 2: ΔΟΜΗ ΠΡΟΓΡΑΜΜΑΤΟΣ C, ΧΕΙΡΙΣΜΟΣ ΜΕΤΑΒΛΗΤΩΝ ΚΑΙ ΣΥΝΑΡΤΗΣΕΙΣ ΕΙΣΟΔΟΥ ΚΑΙ ΕΞΟΔΟΥ

Προγραμματισμός Η/Υ (ΤΛ2007 )

Διαδικασιακός Προγραμματισμός

Πίνακες: μια σύντομη εισαγωγή. Πίνακες χαρακτήρων: τα "Αλφαριθμητικά"

Δομημένος Προγραμματισμός (ΤΛ1006)

ΑΣΚΗΣΗ 7: ΑΛΦΑΡΙΘΜΗΤΙΚΑ

Δομημένος Προγραμματισμός (ΤΛ1006)

Διάλεξη 8η: Αλφαριθμητικά (strings)

Δομημένος Προγραμματισμός (ΤΛ1006)

Διαδικασιακός Προγραμματισμός

Δομημένος Προγραμματισμός. Τμήμα Επιχειρηματικού Σχεδιασμού και Πληροφοριακών Συστημάτων

Τεχνολογία και Προγραμματισμός Υπολογιστών. Η γλώσσα προγραμματισμού C

Διαδικασιακός Προγραμματισμός

Ενδεικτική περιγραφή μαθήματος

Προγραμματισμός Ι. Δείκτες. Δημήτρης Μιχαήλ. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

ΣΥΝΟΠΤΙΚΟΣ ΟΔΗΓΟΣ ΓΛΩΣΣΑΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ C

Προγραμματισμός Ι. Δυναμική Διαχείριση Μνήμης. Δημήτρης Μιχαήλ. Ακ. Έτος Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

Εισαγωγή στον προγραμματισμό. Τμήμα Πληροφορικής & Επικοινωνιών ΤΕΙ Σερρών Εργαστήριο 2

Διαδικασιακός Προγραμματισμός

ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΥΠΟΛΟΓΙΣΤΩΝ & ΥΠΟΛΟΓΙΣΤΙΚΗ ΦΥΣΙΚΗ

Συµβολοσειρές - Strings

Στόχοι και αντικείμενο ενότητας. Εκφράσεις. Η έννοια του τελεστή. #2.. Εισαγωγή στη C (Μέρος Δεύτερο) Η έννοια του Τελεστή

scanf() scanf() stdin scanf() printf() int float double %lf float

ΕΝΤΟΛΕΣ ΕΠΑΝΑΛΗΨΗΣ. for (παράσταση_1; παράσταση_2; παράσταση_3) εντολή επόμενη εντολή

Πίνακες. 1 Πίνακες. 30 Μαρτίου 2014

Η Γλώσσα Προγραμματισμού C (Μέρος 2 - Οι Bασικές Εντολές της C) Οι Βασικοί Τελεστές της C

Η γλώσσα προγραμματισμού C

Διδάσκων: Κωνσταντίνος Κώστα Διαφάνειες: Δημήτρης Ζεϊναλιπούρ

C: Από τη Θεωρία στην Εφαρμογή

2.1. Εντολές Σχόλια Τύποι Δεδομένων

#define, 70, 575 #elif, 580 #else, 580 #endif, 580 #error, 584 #if, 580 #ifdef, 583 #ifndef, 580, 583 #include, 70, 227, 574 #undef, 579

Δομημένος Προγραμματισμός. Τμήμα Επιχειρηματικού Σχεδιασμού και Πληροφοριακών Συστημάτων

Διαδικασιακός Προγραμματισμός

Ανάπτυξη και Σχεδίαση Λογισμικού

Προγραμματισμός Ι. Προχωρημένα Θέματα. Δημήτρης Μιχαήλ. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

Προγραμματισμός Η/Υ. Ενότητα 6: Πίνακες και Δείκτες

Η γλώσσα προγραμματισμού C

int array[10]; double arr[5]; char pin[20]; Προγραµµατισµός Ι

Εισαγωγή στον Προγραμματισμό

ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΥΠΟΛΟΓΙΣΤΩΝ & ΥΠΟΛΟΓΙΣΤΙΚΗ ΦΥΣΙΚΗ

Προγραμματισμός Ι (ΗΥ120)

ΕΙΣΑΓΩΓΗ ΣΤΟΝ ΔΟΜΗΜΕΝΟ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟ

ΠΛΗΡΟΦΟΡΙΚΗ Ι JAVA Τμήμα θεωρίας με Α.Μ. σε 3, 7, 8 & 9 25/10/07

Διαδικαστικός Προγραμματισμός

ΑΡ Χ Ε Ι Α Κ Ε Ι Μ Ε Ν Ο Υ (text files)

5ο σετ σημειώσεων - Δείκτες

Συναρτήσεις διαχείρισης αλφαριθμητικών

Επανάληψη για τις Τελικές εξετάσεις. (Διάλεξη 24) ΕΠΛ 032: ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΜΕΘΟΔΩΝ ΕΠΙΛΥΣΗΣ ΠΡΟΒΛΗΜΑΤΩΝ

Δομημένος Προγραμματισμός (ΤΛ1006)

Προγραμματισμός Ι. Είσοδος/Έξοδος. Δημήτρης Μιχαήλ. Ακ. Έτος Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

ΤΕΜ-101 Εισαγωγή στους Η/Υ Εξεταστική Ιανουαρίου 2011 Θέματα Β

Μεταβλητές τύπου χαρακτήρα

Προγραμματισμός Η/Υ (ΤΛ2007 )

ΑΣΚΗΣΗ 6: ΔΕΙΚΤΕΣ. Σκοπός της Άσκησης. 1. Εισαγωγικά στοιχεία για τους Δείκτες

Κεφάλαιο ΙV: Δείκτες και πίνακες. 4.1 Δείκτες.

Προγραμματισμός Η/Υ (ΤΛ2007 )

Προγραµµατισµός Ι Αλφαριθµητικά Πανεπιστήµιο Πελοποννήσου Τµήµα Πληροφορικής & Τηλεπικοινωνιών Προγραµµατισµός Ι 1 Νικόλαος Δ.

2ο ΓΕΛ ΑΓ.ΔΗΜΗΤΡΙΟΥ ΑΕΠΠ ΘΕΟΔΟΣΙΟΥ ΔΙΟΝ ΠΡΟΣΟΧΗ ΣΤΑ ΠΑΡΑΚΑΤΩ

Διάλεξη 11η: Δείκτες, μέρος 1

Μεθόδων Επίλυσης Προβλημάτων

Δομές Δεδομένων (Εργ.) Ακ. Έτος Διδάσκων: Ευάγγελος Σπύρου. Εργαστήριο 3 Επανάληψη Γ μέρος

Μεθόδων Επίλυσης Προβλημάτων

Επεξεργασία κειμένου και συμβολοσειρών σε C

ΕΡΓΑΣΤΗΡΙΟ 9: Συμβολοσειρές και Ορίσματα Γραμμής Εντολής

Η γλώσσα προγραμματισμού C

Προγραμματισμός Υπολογιστών & Υπολογιστική Φυσική

Προγραμματισμός Η/Υ 1 (Εργαστήριο)

Κεφάλαιο Αλφαριθµητικές Σειρές Χαρακτήρων (Strings)

Εισαγωγή στον Προγραμματισμό

Π. Σταθοπούλου ή Οµάδα Α (Φοιτητές µε µονό αριθµό Μητρώου ) ιδασκαλία : Παρασκευή 11πµ-13µµ ΗΛ7

Transcript:

Εισαγωγή στους Δείκτες (Pointers) Χρησιμοποιήσαμε προηγουμένως τον τελεστή & για να βρούμε τη διεύθυνση της μεταβλητής p. Η &p δηλαδή είναι ένας δείκτης της p. Η πραγματική διεύθυνση είναι ένας 16δικός αριθμός και η συμβολική παράσταση &p είναι μια σταθερά δείκτη. Η μεταβλητή p δεν πρόκειται να αλλάξει διεύθυνση μέσα στο πρόγραμμα, αν και μπορεί να αλλάξει τιμή. Η C έχει και μεταβλητές δείκτη που έχουν μια διεύθυνση ως τιμή. Ακολουθούν παραδείγματα : ptr = &p; /* καταχωρεί τη διεύθυνση της p στην ptr */ ptr = &b; /* ο δείκτης ptr δείχνει τώρα στη b αντί για την p */ Η ptr δηλαδή είναι μια μεταβλητή και η &p είναι μια σταθερά. Για να δηλώσουμε τον τύπο μιας μεταβλητής δείκτη, πρέπει να χρησιμοποιήσουμε τον τελεστή έμμεσης αναφοράς (*). val = *ptr /* βρίσκει την τιμή που δείχνει ο δείκτης ptr */ Πώς δηλώνουμε, όμως, τους δείκτες; Με τη δήλωση μιας μεταβλητής ότι είναι δείκτης, πρέπει ακόμα να πούμε και τι τύπος είναι η μεταβλητή που δείχνει ο δείκτης και αυτό γιατί διαφορετικοί τύποι μεταβλητών απαιτούν διαφορετικό χώρο αποθήκευσης. Οι δείκτες δηλώνονται ως εξής : int *pi; /* pi είναι ένας δείκτης σε μια ακέραια μεταβλητή */ char *pc; /* pc είναι ένας δείκτης σε μια μεταβλητή χαρακτήρα */ float *pf, *pg; /* pf, pg είναι δείκτες σε μεταβλητές float */ Από τα παραπάνω συμπεραίνουμε ότι pi είναι ο δείκτης και ότι η *pi είναι τύπου int. Παρόμοια, η τιμή *pc την οποία δείχνει ο pc είναι τύπου char. Οι Δείκτες και οι Συναρτήσεις Ακολουθεί ένα πρόγραμμα όπου γίνεται επιστροφή τιμών στη συνάρτηση που καλεί.

/* prog40.c χρήση δεικτών για την ανταλλαγή τιμών */ #include <sdtio.h> void interchange(); int x = 5, y = 10; printf("αρχικά x = %d και y = %d. \n", x, y); interchange(&x, &y); /* στείλε τις διευθύνσεις στη συνάρτηση*/ printf("τώρα x = %d και y = %d. \n", x, y); void interchange(u, v) int *u, *v; /* οι u και v είναι τώρα δείκτες */ int temp; temp = *u; /* η temp παίρνει την τιμή που δείχνει η u */ *u = *v; *v = temp; Το αποτέλεσμα θα είναι : Αρχικά x = 5 και y = 10 2

Τώρα x = 10 και y = 5 Ας προσέξουμε τα εξής σημεία : 1. Η κλήση της συνάρτησης γίνεται ως εξής : interchange(&x, &y);, δηλαδή, αντί να στέλνονται οι τιμές των x και y, στέλνονται οι διευθύνσεις τους. Έτσι, τα τυπικά ορίσματα u και v της συνάρτησης interchange() έχουν διευθύνσεις ως τιμές και πρέπει να δηλωθούν ως δείκτες. 2. Εφόσον οι x και y είναι ακέραιοι, δηλώνουμε τις u και v ως δείκτες σε ακέραιους. 3. Θυμηθείτε ότι η u έχει την τιμή &x, έτσι η u δείχνει τη x, δηλαδή η *u μάς δίνει την τιμή του x. 4. Δεν πρέπει να γράψουμε temp = u;, γιατί έτσι θα αποθηκευτεί η διεύθυνση της x και όχι η τιμή της. Θέλουμε μια συνάρτηση να ανταλλάσσει τις τιμές δύο μεταβλητών. Δίνοντας στη συνάρτηση τις διευθύνσεις των μεταβλητών αυτών, αποκτάμε πρόσβαση σ' αυτές τις μεταβλητές. Χρησιμοποιώντας δείκτες και τον τελεστή *, η συνάρτηση μπορεί να εξετάσει τις τιμές που βρίσκονται σ' αυτές τις θέσεις και να τις αλλάξει. Με τους δείκτες δηλαδή μπορούμε να μπούμε στη και να αλλάξουμε ό,τι είναι αποθηκευμένο εκεί. Εισαγωγή στους Πίνακες Ένας πίνακας αποτελείται από μια σειρά στοιχείων ενός τύπου δεδομένων. Το πρόγραμμα πρέπει να γνωρίζει από πόσα στοιχεία αποτελείται ένας πίνακας καθώς και τον τύπο των στοιχείων αυτών. Ο τύπος των στοιχείων ενός πίνακα μπορεί να είναι ένας από τους τύπους μεταβλητών. Ακολουθούν μερικές δηλώσεις πινάκων : float times[365]; /* πίνακας με 365 στοιχεία τύπου float */ char cities[12]; /* πίνακας με 12 στοιχεία τύπου char */ 3

int numbers[50]; /* πίνακας με 50 στοιχεία τύπου int */ Οι αγκύλες [ και ] μάς λένε ότι πρόκειται για πίνακα και ο αριθμός που είναι μέσα στις αγκύλες μάς δείχνει τον αριθμό των στοιχείων του πίνακα. Για να αναφερθούμε σ ένα συγκεκριμένο στοιχείο του πίνακα, χρησιμοποιούμε έναν αριθμό που ονομάζεται δείκτης πίνακακαι που η αρίθμησή του αρχίζει από το 0. Ο πίνακας δηλ. είναι μια μεταβλητή με δείκτη και για να αναφερθούμε πλήρως σ ένα στοιχείο του, χρειαζόμαστε το όνομα του πίνακα και την τιμή του δείκτη του πίνακα. Έτσι, π.χ. το times[0] είναι το πρώτο στοιχείο του πίνακα times και το times[364] είναι το 365 ο και τελευταίο στοιχείο του. Αυτόματες, Εξωτερικές και Στατικές Μεταβλητές Μια αυτόματη μεταβλητή ή ένας αυτόματος πίνακας είναι μια μεταβλητή ή ένας πίνακας που ορίζεται μέσα σε μια συνάρτηση. Όπως ήδη ξέρουμε, μια μεταβλητή που ορίζεται μέσα σε μια συνάρτηση (τοπική μεταβλητή), ανήκει σ' αυτή τη συνάρτηση και το όνομά της μπορεί να ξαναχρησιμοποιηθεί και αλλού. Όταν τελειώσει η κλήση της συνάρτησης, τότε απελευθερώνεται ο χώρος της μνήμης που χρησιμοποιήθηκε για τις τοπικές της μεταβλητές. Μπορούμε να δώσουμε αρχικές τιμές σ αυτόματους πίνακες ως εξής : int powers[8] = 1, 2, 4, 6, 8, 16, 32, 64; Επειδή ο πίνακας ορίζεται μέσα στη, είναι ένας αυτόματος πίνακας και η απόδοση αρχικών τιμών σ' αυτόν γίνεται με τη χρήση μιας λίστας τιμών που χωρίζονται με κόμμα και που είναι κλεισμένες σε αγκύλες. Μια εξωτερική μεταβλητή ή ένας εξωτερικός πίνακας είναι μια μεταβλητή ή ένας πίνακας που ορίζεται έξω από μια συνάρτηση. 4

Ακολουθεί ένα παράδειγμα : int report; int numbers[5] = 12, 10, 8, 9, 6;... int feed(n) int n;... Οι εξωτερικές μεταβλητές διαφέρουν από τις αυτόματες στο ότι μπορούν να χρησιμοποιηθούν απ' όλες τις συναρτήσεις ενός προγράμματος, παραμένουν για όσο χρόνο εκτελείται ένα πρόγραμμα και δεν χάνονται όταν τελειώνει μια συγκεκριμένη συνάρτηση. Ακόμη, έχουν αρχική τιμή μηδέν όταν δεν ορίζεται κάτι άλλο. Έτσι, η μεταβλητή report στο παραπάνω πρόγραμμα έχει αρχική τιμή ίση με 0. Μια στατική μεταβλητή ή ένας στατικός πίνακας ορίζονται μέσα σε μια συνάρτηση με τη λέξη-κλειδί static : int account(n,m) int n, m; static int beans[2] = 343, 332;... 5

Μια μεταβλητή που δηλώνεται με τη λέξη-κλειδί static μπορεί να είναι τοπική σε μια συνάρτηση, αλλά διατηρεί τις τιμές της μεταξύ των κλήσεων μιας συνάρτησης και της αποδίδεται αρχική τιμή ίση με 0, όταν βέβαια δεν δηλώνεται κάτι άλλο. Απόδοση Αρχικών Τιμών σε Πίνακες Ακολουθεί ένα πρόγραμμα που καταχωρεί τον αριθμό των ημερών ανά μήνα σ έναν πίνακα με απόδοση αρχικών τιμών και μετά τους εκτυπώνει. /* prog41.c απόδοση αρχικών τιμών στις ημέρες κάθε μήνα */ #include <stdio.h> #define MONTHS 12 int days[months] = 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31; int index; for (index=0; index<months; index++) printf ("Ο μήνας %d έχει %d ημέρες.\n", index+1, days[index]); Το αποτέλεσμα θα είναι ως εξής : Ο μήνας 1 έχει 31 ημέρες. Ο μήνας 2 έχει 28 ημέρες. Ο μήνας 3 έχει 31 ημέρες. Ο μήνας 4 έχει 30 ημέρες. 6

Ο μήνας 5 έχει 31 ημέρες. Ο μήνας 6 έχει 30 ημέρες. Ο μήνας 7 έχει 31 ημέρες. Ο μήνας 8 έχει 31 ημέρες. Ο μήνας 9 έχει 30 ημέρες. Ο μήνας 10 έχει 31 ημέρες. Ο μήνας 11 έχει 30 ημέρες. Ο μήνας 12 έχει 31 ημέρες. Βλέπουμε στο παραπάνω παράδειγμα ότι ο αριθμός των στοιχείων της λίστας πρέπει να είναι ίδιος με το μέγεθος του πίνακα. Αν δώσουμε περισσότερα στοιχεία σ έναν πίνακα απ' ό,τι είναι το δηλωμένο μέγεθός του, τότε αυτό θεωρείται λάθος. Καταχώρηση Τιμών σε Πίνακες Ακολουθεί ένα πρόγραμμα που καταχωρεί άρτιους αριθμούς σ έναν αυτόματο πίνακα : #include <stdio.h> #define SIZE 20 int counter, evens[size]; for (counter=0; counter<size; counter++) evens[counter] = 2 * counter; 7

Η C, όμως, δεν επιτρέπει την καταχώρηση τιμών από έναν πίνακα σ έναν άλλον, ούτε μπορούμε να χρησιμοποιήσουμε τη μορφή της λίστας στοιχείων μέσα σε αγκύλες, εκτός κι αν πρόκειται για απόδοση αρχικών τιμών. Ακολουθεί ένα πρόγραμμα που μας λέει τι δεν μπορούμε να κάνουμε με τους πίνακες στη C : #include <stdio.h> #define SIZE 5 int pina[size] = 5, 3, 2, 8; /* όλα εντάξει */ int pinb[size]; pinb = pina; /* δεν επιτρέπεται */ pinb[size] = pina[size]; /* ανεπίτρεπτο */ pinb[size] = 5, 3, 2, 8; /* δεν δουλεύει εδώ */ Δείκτες σε Πίνακες Είδαμε στα προηγούμενα ότι οι δείκτες (pointers) αποτελούν έναν συμβολικό τρόπο για να χρησιμοποιούμε διευθύνσεις μεταβλητών. Στην πραγματικότητα, ο συμβολισμός των πινάκων είναι μια μεταμφιεσμένη χρήση των δεικτών. Το όνομα ενός πίνακα είναι και ένας δείκτης, που δείχνει στο πρώτο στοιχείο του. Δηλαδή, αν pina είναι ένας πίνακας, τότε με : pina == &pina[0] παριστάνεται και η διεύθυνση μνήμης του πρώτου στοιχείου του πίνακα. 8

Ακολουθεί ένα παράδειγμα που κάνει πράξεις με τις τιμές ενός δείκτη : /* prog42.c πρόσθεση δείκτη */ #include <stdio.h> #define SIZE 4 int pina[size], *pti, index; float pinb[size], *ptf; pti = pina; /* καταχωρεί τη διεύθυνση του πίνακα σε δείκτη */ ptf = pinb; for (index=0; index<size; index++) printf("δείκτες + %d : %10u %10u\n", index, pti+index, ptf+index); Το αποτέλεσμα θα είναι ως εξής : δείκτες + 0 : 56014 56026 δείκτες + 1 : 56016 56030 δείκτες + 2 : 56018 56034 δείκτες + 3 : 56020 56038 9

Στην πρώτη γραμμή τυπώνονται οι πρώτες διευθύνσεις των δύο πινάκων, όποιες είναι αυτές. Στην επόμενη γραμμή βλέπουμε το αποτέλεσμα της πρόσθεσης του 1 στη διεύθυνση. Για να δούμε τι γίνεται από κοντά : 56014 + 1 = 56016 ; 56026 + 1 = 56030 ; Ξέρουμε ότι ο τύπος int χρησιμοποιεί 2 bytes για αποθήκευση και ο τύπος float 4 bytes. Όταν λοιπόν προσθέτουμε 1 στον αντίστοιχο δείκτη, τότε η C προσθέτει μια μονάδα αποθήκευσης. Για τους πίνακες, όμως, αυτό σημαίνει ότι η διεύθυνση αυξάνεται στη διεύθυνση του επόμενου στοιχείου και όχι στο επόμενο byte. Προσθέτοντας έναν ακέραιο σ' έναν δείκτη ή αυξάνοντας έναν δείκτη, αλλάζει η τιμή του δείκτη κατά τον αριθμό των bytes του στοιχείου που δείχνει ο δείκτης. Ακολουθούν μερικές ενδιαφέρουσες εκφράσεις : dates + 2 == &dates[2] /* ίδια διεύθυνση */ *(dates + 2) == dates[2] /* ίδια τιμή */ Αυτές οι ισότητες δείχνουν τη στενή σχέση μεταξύ πινάκων και δεικτών. Αυτό σημαίνει ότι μπορούμε να χρησιμοποιήσουμε ένα δείκτη για να προσδιορίσουμε ένα συγκεκριμένο στοιχείο ενός πίνακα και να πάρουμε την τιμή του. Δεν πρέπει, όμως, να συγχέουμε την τιμή της *(dates+2) με την τιμή *dates+2, γιατί : *(dates + 2) /* είναι η τιμή του 3ου στοιχείου του πίνακα dates */ *dates + 2 /* το 2 προστίθεται στην τιμή του 1ου στοιχείου */ Μπορούμε συνεπώς να χρησιμοποιούμε και δείκτες για να δουλέψουμε με τους πίνακες. Ακολουθεί ένα πρόγραμμα που κάνει την ίδια δουλειά με το πρόγραμμα που είδαμε προηγουμένως, μόνο που τώρα χρησιμοποιούμε δείκτες αντί για πίνακες : /* prog43.c χρησιμοποιεί δείκτες αντί για πίνακες */ #include <stdio.h> #define MONTHS 12 10

int days[months] = 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31; int index; for (index=0; index<months; index++) printf ("Ο μήνας %d έχει %d ημέρες.\n", index+1, *(days+index)); Συναρτήσεις, Πίνακες και Δείκτες Η C δεν επιτρέπει ολόκληροι πίνακες να είναι ορίσματα μιας συνάρτησης, αλλά για να κάνουμε τη δουλειά μας μπορούμε να περάσουμε (μεταβιβάσουμε) τη διεύθυνση ενός πίνακα σε μια συνάρτηση. Η συνάρτηση μπορεί μετά να χρησιμοποιήσει αυτήν την τιμή για τον χειρισμό του πρωτότυπου πίνακα. Είναι ένα κλασσικό παράδειγμα όπου πρέπει να χρησιμοποιήσουμε δείκτες για τον χειρισμό ενός πίνακα. Μπορούμε να χρησιμοποιήσουμε είτε συμβολισμό πίνακα είτε συμβολισμό δείκτη μέσα στη συνάρτηση. Ακολουθεί ένα παράδειγμα με μια συνάρτηση που επιστρέφει το άθροισμα των στοιχείων ενός πίνακα. /* prog44.c άθροισμα στοιχείων ενός πίνακα */ #include <stdio.h> #define SIZE 10 long sum(); 11

static int pina[size] = 20, 10, 5, 39, 4, 16, 19, 26, 31, 20; long answer; answer = sum(pina, SIZE); printf("το άθροισμα των στοιχείων είναι %d.\n", answer); long sum(ar,n) /* χρήση δείκτη */ int *ar; /* ο ar είναι ένας δείκτης */ int n; int i; long total = 0; for (i=0; i<n; i++) return total; total += *ar; /* πρόσθεση τιμής στο total */ ar++; /* ο δείκτης στο επόμενο στοιχείο */ Ο ar ξεκινάει δείχνοντας το πρώτο στοιχείο του πίνακα pina και με την πρόταση καταχώρησης total += *ar προστίθεται η τιμή του πρώτου στοιχείου, δηλ. η 20, στη 12

μεταβλητή total. Μετά, η έκφραση ar++ αυξάνει τη μεταβλητή δείκτη ar έτσι ώστε αυτή να δείχνει στο επόμενο στοιχείο του πίνακα. Μπορούμε να γράψουμε τις προηγούμενες δύο εντολές και έτσι : total += *ar++; Δηλαδή, αυξάνεται ο δείκτης κατά ένα και όχι η τιμή που δείχνει και μάλιστα αυξάνεται μετά τη χρήση της τιμής του. Εάν χρησιμοποιήσουμε *++ar, τότε η σειρά θα ήταν : αύξηση του δείκτη και μετά χρήση της τιμής που δείχνει. Αλλά αν χρησιμοποιήσουμε την έκφραση (*ar)++, τότε το πρόγραμμα θα κάνει χρήση της τιμής που δείχνει η ar και μετά θα αυξήσει την τιμή αυτή κατά ένα και όχι τον δείκτη. Οι Λειτουργίες των Δεικτών Η C έχει πέντε βασικές λειτουργίες δεικτών. Για να δούμε από κοντά τα αποτελέσματα της κάθε λειτουργίας, τυπώνουμε την τιμή του δείκτη, δηλ. τη διεύθυνση που δείχνει, την τιμή που είναι αποθηκευμένη στη διεύθυνση που δείχνει ο δείκτης και ακόμη και τη διεύθυνση του ίδιου του δείκτη. Ακολουθεί ένα παράδειγμα : /* prog45.c λειτουργίες δεικτών */ #include <stdio.h> static int pina[3] = 100, 200, 300; int *ptr1, *ptr2; ptr1 = pina;/* καταχώρηση της διεύθυνσης του πίνακα σ' έναν δείκτη */ ptr2 = &pina[2]; /* καταχώρηση της διεύθυνσης του 3ου στοιχείου */ printf("ptr1 = %u, *ptr1 = %d, &ptr1 = %u\n", ptr1, *ptr1, &ptr1); 13

ptr1++; /* αυξάνουμε τον δείκτη */ printf("ptr1 = %u, *ptr1 = %d, &ptr1 = %u\n", ptr1, *ptr1, &ptr1); printf("ptr2 = %u, *ptr2 = %d, &ptr2 = %u\n", ptr2, *ptr2, &ptr2); ++ptr2; /* περνάμε τα όρια του πίνακα */ printf("ptr2 = %u, *ptr2 = %d, &ptr2 = %u\n", ptr2, *ptr2, &ptr2); printf("ptr2 - ptr1 = %u\n", ptr2 - ptr1); /* τυπώνουμε τη διαφορά των δεικτών */ Το αποτέλεσμα θα είναι ως εξής : ptr1 = 234, *ptr1 = 100, &ptr1 = 3606 ptr1 = 236, *ptr1 = 200, &ptr1 = 3606 ptr2 = 238, *ptr2 = 300, &ptr2 = 3604 ptr2 = 240, *ptr2 = 1910, &ptr2 = 3604 ptr2 ptr1 = 2 Ας δούμε από κοντά τις πέντε βασικές λειτουργίες που μπορούμε να κάνουμε με τις μεταβλητές δείκτη : 1. Καταχώρηση. Μπορούμε να καταχωρήσουμε μια διεύθυνση σ' έναν δείκτη, είτε χρησιμοποιώντας ένα όνομα πίνακα ή χρησιμοποιώντας τον τελεστή διεύθυνσης & και την τιμή μιας μεταβλητής. 2. Εύρεση τιμής. Ο τελεστής * μάς δίνει την τιμή που βρίσκεται αποθηκευμένη στη θέση που δείχνεται από τον δείκτη. 3. Απόκτηση της διεύθυνσης ενός δείκτη. Και οι μεταβλητές δείκτη έχουν μια διεύθυνση και μια τιμή. 14

4. Αύξηση-μείωση ενός δείκτη. Με την αύξησή του ένας δείκτης μετακινείται στο επόμενο στοιχείο του πίνακα. Φυσικά, με ανάλογο τρόπο μπορούμε και να μειώσουμε έναν δείκτη. Η λειτουργία, όμως, ++ptr2 στο προηγούμενο παράδειγμα είχε σαν αποτέλεσμα ο ptr2 να μετακινηθεί κατά δύο bytes και να δείχνει ο,τιδήποτε μπορεί να αποθηκευθεί μετά τον πίνακα. Επίσης, πρέπει να θυμόμαστε ότι μπορούμε να χρησιμοποιούμε τους τελεστές αύξησης ή μείωσης με τις μεταβλητές δείκτη, αλλά όχι με σταθερές δείκτη. Δηλαδή, το ptr2 = urn++; δεν επιτρέπεται, όπως δεν επιτρέπεται και το 3++. 5. Διαφορά. Μπορούμε να βρούμε τη διαφορά μεταξύ δύο δεικτών. Οι Πίνακες Πολλών Διαστάσεων Ένας μετεωρολόγος θέλει να αναλύσει τα δεδομένα της μηνιαίας βροχόπτωσης σε μια διάρκεια 5 ετών, δηλ. θα χρειαστεί συνολικά 5 Χ 12 = 60 μεταβλητές. Για να παραστήσει αυτά τα δεδομένα μπορεί να χρησιμοποιήσει 60 ανεξάρτητες μεταβλητές, μία για κάθε στοιχείο δεδομένων, κάτι φυσικά πολύ άβολο. Κάτι καλύτερο θα ήταν ένας πίνακας με 60 στοιχεία, αλλά ακόμα καλύτερο θα ήταν αν μπορούσε να κρατήσει ξεχωριστά τα 12 δεδομένα για τον κάθε χρόνο. Μπορεί δηλαδή να χρησιμοποιήσει 5 πίνακες, έναν για τα 12 στοιχεία του κάθε έτους, αλλά τι γίνεται αν τα έτη αυξηθούν και γίνουν 50; Μια καλή λύση είναι να χρησιμοποιήσουμε έναν πίνακα από πίνακες. Δηλ., ο κύριος πίνακας θα έχει 5 στοιχεία και το κάθε στοιχείο του θα είναι ένας πίνακας από 12 στοιχεία. Μιλάμε δηλαδή για πίνακα δύο διαστάσεων. Αυτό γίνεται ως εξής : static float rain[5][12]; Ο πίνακας rain είναι δισδιάστατος και αποτελείται από 5 γραμμές και από 12 στήλες. Αν αλλάξουμε τον δεύτερο δείκτη, κινούμαστε σε μια γραμμή και αν αλλάξουμε τον πρώτο δείκτη, κινούμαστε κατά μήκος μιας στήλης. Για το συγκεκριμένο παράδειγμα, ο δεύτερος δείκτης δείχνει τους μήνες και ο πρώτος τα χρόνια. Ας δούμε κι ένα πρόγραμμα μ αυτόν τον δισδιάστατο πίνακα. Ο στόχος του προγράμματος είναι να βρεθεί η συνολική βροχόπτωση για κάθε χρόνο, η μέση ετήσια βροχόπτωση και η μέση μηνιαία βροχόπτωση. Για να βρούμε τη συνολική βροχόπτωση του κάθε χρόνου, πρέπει να προσθέσουμε όλα τα δεδομένα του κάθε χρόνου, δηλ. της κάθε γραμμής. Για να βρούμε τη μέση 15

βροχόπτωση για κάποιον μήνα, πρέπει να προσθέσουμε όλα τα δεδομένα σε μια δοσμένη στήλη. Σταθερές Συμβολοσειράς Χαρακτήρα Όταν ο μεταγλωττιστής της C συναντά κάτι ανάμεσα σε διπλά εισαγωγικά " ", το θεωρεί σαν σταθερά συμβολοσειράς και οι χαρακτήρες μέσα στα εισαγωγικά αυτά μαζί με τον χαρακτήρα '\0' αποθηκεύονται σε γειτονικές θέσεις της μνήμης. Εάν, όμως, θέλουμε να χρησιμοποιήσουμε μέσα σε μια συμβολοσειρά διπλά εισαγωγικά, τότε πρέπει να βάλουμε πριν απ αυτά μια πλάγια κάθετο, ως εξής : printf("\"τρέξε, Μαρία!\" είπε η Βάσω.\n"); Το αποτέλεσμα θα είναι το εξής : "Τρέξε, Μαρία!" είπε η Βάσω. Όλη η φράση μέσα στα εισαγωγικά δρα σαν δείκτης, εκεί που αποθηκεύεται η συμβολοσειρά, κάτι δηλ. ανάλογο με το όνομα ενός πίνακα, που δρα σαν ένας δείκτης στη θέση του πίνακα. Πίνακες Συμβολοσειράς Χαρακτήρα Μπορούμε να δώσουμε αρχικές τιμές σε μια συμβολοσειρά χαρακτήρα ως εξής: char line[ ] = "Περιορίσου σε μια γραμμή"; Θα μπορούσαμε να κάνουμε το ίδιο και με τον γνωστό τρόπο απόδοσης αρχικών τιμών σ έναν πίνακα ως εξής : char line[ ] = 'Π', 'ε', 'ρ', 'ι', 'ο', 'ρ', 'ί', 'σ', 'ο', 'υ', ' ', 'σ', 'ε', ' ', 'μ', 'ι', 'α', ' ', 'γ', 'ρ', 'α', 'μ', 'μ', 'ή', '\0'; H χρήση του μηδενικού χαρακτήρα '\0' εξηγεί ότι πρόκειται για συμβολοσειρά και όχι για πίνακα χαρακτήρων. Και στις δύο μορφές, ο μεταγλωττιστής μετράει τους χαρακτήρες και δίνει στον πίνακα το αντίστοιχο μέγεθος. Όπως συμβαίνει και με τους άλλους πίνακες, το όνομα του πίνακα line είναι ένας δείκτης στο πρώτο στοιχείο του πίνακα : 16

line == &line[0] *line == 'Π' *(line+1) == line[1] == 'ε' Μπορούμε συνεπώς να χρησιμοποιήσουμε τον συμβολισμό δείκτη για να δημιουργήσουμε μια συμβολοσειρά : char *Florina = "\nflorina per sempre"; που ισοδυναμεί με το : static char Florina[ ] = "\nflorina per sempre"; Είσοδος Συμβολοσειράς Για το διάβασμα μιας συμβολοσειράς σ' ένα πρόγραμμα, πρέπει να κάνουμε δύο πράγματα : να δεσμεύσουμε τον χώρο αποθήκευσης γι αυτή τη συμβολοσειρά και να χρησιμοποιήσουμε μια συνάρτηση εισόδου για το διάβασμά της. Ο πιο απλός τρόπος για να δηλώσουμε με σαφήνεια το μέγεθος ενός πίνακα είναι η εξής δήλωση : char name[81]; Αφού έχει δημιουργηθεί χώρος στη μνήμη για τη συμβολοσειρά, μπορούμε πλέον να τη διαβάσουμε. Θα δούμε τις συναρτήσεις διαβάσματος συμβολοσειρών gets() και scanf(). Η Συνάρτηση gets() Η συνάρτηση αυτή διαβάζει χαρακτήρες μέχρι να συναντήσει τον χαρακτήρα enter '\n'. Η συνάρτηση αυτή δέχεται όλους τους χαρακτήρες πριν από τον χαρακτήρα '\n', προσθέτει τον μηδενικό χαρακτήρα '\0' και δίνει τη συμβολοσειρά στο καλούν πρόγραμμα. Ο χαρακτήρας νέας γραμμής διαβάζεται και αγνοείται. Ακολουθεί ένα απλό παράδειγμα χρήσης της συνάρτησης gets() : /* prog46.c διάβασμα ενός ονόματος */ #include <stdio.h> 17

#define MAX 81 char name[max]; /* δέσμευση χώρου */ printf("γεια σου, ποιο είναι το όνομά σου ;\n"); gets(name); printf("γεια σου, %s.\n", name); Αν όλα δουλέψουν σωστά, η gets() επιστρέφει τη διεύθυνση της συμβολοσειράς που διάβασε, αν όμως κάτι πάει στραβά ή αν η gets() συναντήσει EOF, επιστρέφει μια μηδενική διεύθυνση ή τίποτα. Η κενή διεύθυνση καλείται δείκτης κενού, παριστάνεται στο αρχείο <stdio.h> με τη σταθερά NULL και δεν έχει φυσικά καμία σχέση με τον χαρακτήρα του κενού διαστήματος. Έτσι, με τη gets() μπορούμε να ελέγχουμε για πιθανά λάθη ως εξής : while (gets(name)!= NULL) Η Συνάρτηση scanf() Η βασική διαφορά των δύο συναρτήσεων είναι στον τρόπο που αποφασίζουν ότι έχουν φθάσει στο τέλος της συμβολοσειράς. Μπορούμε να πούμε ότι η scanf() είναι περισσότερο μια συνάρτηση "απόκτησης λέξης" παρά "απόκτησης συμβολοσειράς". Η συνάρτηση scanf() έχει δύο επιλογές. Ξεκινά πάντα με τον πρώτο μη-λευκό χαρακτήρα που συναντάει. Αν χρησιμοποιούμε τον προσδιοριστή %s, η συμβολοσειρά φθάνει μέχρι τον επόμενο λευκό χαρακτήρα χωρίς να τον περιλαμβάνει. Αν καθορίσουμε ένα εύρος πεδίου, π.χ. %10s, τότε η scanf() λαμβάνει υπόψη της μέχρι 10 χαρακτήρες ή μέχρι τον πρώτο λευκό χαρακτήρα. 18

Όπως είδαμε και στα προηγούμενα, η τιμής επιστροφής της scanf() είναι μια ακέραια τιμή, που είναι ίση με το αριθμό των στοιχείων που διαβάστηκαν με επιτυχία ή με τον χαρακτήρα EOF αν συναντήσει το τέλος αρχείου. Ακολουθεί ένα παράδειγμα : /* prog47. c χρήση της scanf() */ #include <stdio.h> static char name1[11], name2[11]; int count; printf("παρακαλώ δώστε 2 ονόματα. \n"); count = scanf("%5s %10s", name1, name2); printf("διάβασα τα %d ονόματα %s και %s. \n", count, name1, name2); Το αποτέλεσμα θα είναι : Παρακαλώ δώστε 2 ονόματα. Τάκης Αντώνης Διάβασα τα 2 ονόματα Τάκης και Αντώνης. ή Παρακαλώ δώστε 2 ονόματα. Λένα Παπαδημητρίου Διάβασα τα 2 ονόματα Λένα και Παπαδημητρ. 19

Αν έχουμε να δώσουμε μόνο κείμενο από το πληκτρολόγιο, τότε είναι καλύτερα να χρησιμοποιήσουμε τη συνάρτηση gets(), ενώ η scanf() συνιστάται για την είσοδο μικτών τύπων σε μια τυποποιημένη μορφή, όπως π.χ. αν κάθε γραμμή εισόδου περιέχει το όνομα ενός εργαλείου, τον κωδικό του αριθμού και την τιμή του. Έξοδος Συμβολοσειράς Θα δούμε δύο συναρτήσεις εξόδου, τις puts() και printf(). Η Συνάρτηση puts() Η συνάρτηση puts() είναι αρκετά εύκολη στη χρήση και απλά δίνουμε ένα όρισμα που είναι ένας δείκτης σε μια συμβολοσειρά. Ακολουθεί ένα παράδειγμα : /* prog48.c χρήση της puts */ #include <stdio.h> #define DEF "Είμαι μια συμβολοσειρά που έχει ορισθεί." static char str1[ ] = "Ένας πίνακας μού απέδωσε αρχικές τιμές."; char *str2 = "Ένας δείκτης μού απέδωσε αρχικές τιμές."; puts("είμαι ένα όρισμα στην puts()."); puts(def); puts(str1); puts(str2); 20

puts(&str1[4]); puts(str2+4); Το αποτέλεσμα θα είναι : Είμαι ένα όρισμα στην puts(). Είμαι μια συμβολοσειρά που έχει ορισθεί. Ένας πίνακας μού απέδωσε αρχικές τιμές. Ένας δείκτης μού απέδωσε αρχικές τιμές. πίνακας μού απέδωσε αρχικές τιμές. δείκτης μού απέδωσε αρχικές τιμές. Προσέχουμε στα δύο τελευταία παραδείγματα από πού αρχίζει να τυπώνει η puts. Κάθε συμβολοσειρά με την puts() εμφανίζεται σε μια νέα γραμμή. Η Συνάρτηση printf() Όπως ήδη γνωρίζουμε, η printf() δεν τοποθετεί αυτόματα κάθε συμβολοσειρά σε μια νέα γραμμή, αλλά εμείς πρέπει να δείξουμε πού θέλουμε να ξεκινούν οι νέες γραμμές. Γενικά, με την printf() πρέπει να γράψουμε περισσότερα, αλλά μ αυτήν μπορούμε να συνδυάσουμε σε μια γραμμή πολλές συμβολοσειρές. Η Συνάρτηση strlen() Η συνάρτηση αυτή βρίσκει το μήκος μιας συμβολοσειράς. Ακολουθεί ένα πρόγραμμα όπου μπορούμε να μικρύνουμε μια μεγάλη συμβολοσειρά σε μέγιστο μήκος χαρακτήρων ίσο με size : /* prog49.c προκρούστεια συνάρτηση */ 21

void match(string, size) char *string; int size; if (strlen(string) > size) *(string + size) = '\0'; Η Συνάρτηση strcat() Με τη συνάρτηση strcat() μπορούμε να ενώσουμε συμβολοσειρές : /* prog50.c ένωση δύο συμβολοσειρών */ #include <stdio.h> #include <string.h> #define SIZE 80 static char color[size]; static char addon[ ] = ", πολύ ωραίο χρώμα"; puts("ποιο είναι το αγαπημένο σου χρώμα;"); gets(color); strcat(color, addon); 22

puts(color); puts(addon); Το αποτέλεσμα θα είναι : Ποιο είναι το αγαπημένο σου χρώμα; Κόκκινο Κόκκινο, πολύ ωραίοα χρώμα, πολύ ωραίο χρώμα Όπως βλέπουμε, η συνάρτηση strcat() δέχεται δύο συμβολοσειρές ως ορίσματα. Ένα αντίγραφο της δεύτερης συμβολοσειράς τοποθετείται στο τέλος της πρώτης και οι δύο μαζί παίρνουν τη θέση της πρώτης, ενώ η δεύτερη συμβολοσειρά δεν αλλάζει. Πρέπει, όμως, να κάνουμε και έλεγχο του μεγέθους της πρώτης συμβολοσειράς για να μην έχουμε αποκοπές χαρακτήρων. Η Συνάρτηση strcmp() Η συνάρτηση strcmp() συγκρίνει τα περιεχόμενα δύο συμβολοσειρών και όχι τις διευθύνσεις τους. Ακολουθεί ένα πρόγραμμα : /* prog51.c σύγκριση δύο συμβολοσειρών */ #include <stdio.h> #include <string.h> #define ANSWER "Βέροια" #define MAX 40 23

char try[max]; puts("ποια είναι η πρωτεύουσα της Ημαθίας;"); gets(try); while ((strcmp(try, ANSWER)!= 0)) puts("λάθος. Προσπάθησε ξανά."); gets(try); puts("μπράβο! Σωστή απάντηση!"); Η συνάρτηση strcmp() δέχεται δύο δείκτες συμβολοσειράς σαν ορίσματα και επιστρέφει μια τιμή 0 αν οι δύο συμβολοσειρές είναι ίδιες. Η strcmp() επιστρέφει ακόμη έναν αρνητικό αριθμό εάν η πρώτη συμβολοσειρά προηγείται αλφαβητικά της δεύτερης και έναν θετικό αριθμό στην αντίθετη περίπτωση. Η Συνάρτηση strcpy() Η συνάρτηση αυτή αντιγράφει συμβολοσειρές. Ακολουθεί ένα παράδειγμα : /* prog52.c επίδειξη της strcpy() */ #include <stdio.h> #include <string.h> #define MOTO "Florina per sempre" 24

#define SIZE 20 static char *second = MOTO; static char first[size] = "Florina"; puts(second); puts(first); strcpy(first, second); puts(second); puts(first); Το αποτέλεσμα θα είναι : Florina per sempre Florina Florina per sempre Florina per sempre Η συμβολοσειρά που δείχνεται από το δεύτερο όρισμα αντιγράφεται στον πίνακα που δείχνεται από το πρώτο όρισμα. Για τη συμβολοσειρά-στόχο, πρέπει να προσέχουμε τη δήλωση του μεγέθους της. Η Συνάρτηση sprintf() Αυτή δηλώνεται στο αρχείο stdio.h και όχι στο string.h και δουλεύει όπως η printf(), αλλά με τη διαφορά ότι γράφει σε μια συμβολοσειρά αντί να εμφανίζει στην οθόνη, 25

δηλ. μας δίνει έναν τρόπο για τον συνδυασμό διαφόρων συμβολοσειρών σε μια συμβολοσειρά. Το πρώτο όρισμα της sprintf() είναι η διεύθυνση της τελικής συμβολοσειράς και τα υπόλοιπα ορίσματα είναι τα ίδια όπως και για την printf() : char first = "Florina"; char second = " per sempre"; char pina[20]; sprintf(pina, "%s %s", first, second); Με τις παραπάνω εντολές αντιγράφεται η συμβολοσειρά "Florina per sempre" στον πίνακα pina. Οι Συναρτήσεις του Αρχείου ctype.h Το αρχείο επικεφαλίδων ctype.h περιέχει μια οικογένεια από συναρτήσεις χαρακτήρα, που είναι οι εξής : Όνομα Αληθής (True) αν το Όρισμα είναι : isalnum() isalpha() iprgtrl() isdigit() isgraph() islower() isprint() ispunct() isspace() Αλφαριθμητικό Αλφαβητικό Ένας χαρακτήρας ελέγχου, π.χ. Control-B Ένα ψηφίο Οποιοσδήποτε εκτυπούμενος μη μηδενικός χαρακτήρας Ένα μικρό γράμμα Ένας εκτυπούμενος χαρακτήρας Ένας χαρακτήρας σημείου στίξης Ένας λευκός χαρακτήρας 26

isupper() isxdigit() Ένα κεφαλαίο γράμμα Ένας χαρακτήρας σε 16δική μορφή Υπάρχουν δύο ακόμη συναρτήσεις, η toupper() που μετατρέπει πεζά γράμματα σε κεφαλαία και η tolower() που κάνει το αντίστροφο. Ακολουθεί ένα πρόγραμμα που δέχεται ως είσοδο μια γραμμή και αντιστρέφει τα γράμματα από κεφαλαία σε πεζά και από πεζά σε κεφαλαία. /* prog53.c τροποποίηση μιας συμβολοσειράς */ #include <stdio.h> #include <string.h> #include <ctype.h> #define LIMIT 80 char line[limit]; void modify(); puts("παρακαλώ, εισάγετε μια γραμμή:"); gets(line); modify(line); puts(line); void modify(str) char *str; 27

while (*str!= '\0') if (isupper(*str)) *str = tolower(*str); else if (islower(*str)) *str = toupper(*str); srt++; Μετατροπή Συμβολοσειράς σε Αριθμό Για να μετατρέψουμε μια συμβολοσειρά σε αριθμό, μπορούμε να χρησιμοποιήσουμε τη συνάρτηση atoi() που δέχεται μια συμβολοσειρά ως όρισμα και επιστρέφει την αντίστοιχη ακέραια τιμή. Για να δουλέψει αυτή η συνάρτηση πρέπει να συμπεριλάβουμε το αρχείο stdlib.h. Αυτό το αρχείο περιλαμβάνει δηλώσεις και για τις συναρτήσεις atof() και atol(), όπου η μεν πρώτη μετατρέπει μια συμβολοσειρά σε μια τιμή τύπου double και η δεύτερη μετατρέπει μια συμβολοσειρά σε μια τιμή τύπου long. 28