Δείκτες στην C (επανάληψη)

Σχετικά έγγραφα
Εισαγωγή στον Προγραμματισμό

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

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

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

Διάλεξη 6: Δείκτες και Πίνακες

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

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

Δείκτες (Pointers) Ένας δείκτης είναι μια μεταβλητή με τιμή μια διεύθυνση μνήμης. 9.8

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

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

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

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

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

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

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

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

Δείκτες (Pointers) Ένας δείκτης είναι μια μεταβλητή με τιμή μια διεύθυνση μνήμης. 9.8

είκτες και Πίνακες (2)

Βαθμός Σχόλια. lab6 PASS PASS. - Πολύ καλή δουλειά, αλλά προσπάθησε να κάνεις την άσκηση χρησιµοποιώντας συναρτήσεις από το string.

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

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

Α. unsigned int Β. double. Γ. int. unsigned char x = 1; x = x + x ; x = x * x ; x = x ^ x ; printf("%u\n", x); Β. unsigned char

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

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

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

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

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

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

Εισαγωγή στον Προγραµµατισµό. Πανεπιστήµιο Θεσσαλίας Τµήµα Ηλεκτρολόγων Μηχανικών και Μηχανικών Η/Υ

ΠΑΝΕΠΙΣΤΗΜΙΟ ΘΕΣΣΑΛΙΑΣ ΣΧΟΛΗ ΘΕΤΙΚΩΝ ΕΠΙΣΤΗΜΩΝ ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ

Διάλεξη 5: Δείκτες και Συναρτήσεις

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

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

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

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

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

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

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

ΣΧΕΔΙΑΣΗ ΚΑΙ ΥΛΟΠΟΙΗΣΗ ΛΟΓΙΣΜΙΚΟΥ

Διάλεξη 13η: Δυναμική Διαχείρηση Μνήμης, μέρος 1

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

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

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

Η βασική συνάρτηση προγράμματος main()

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

Διδάσκων: Παναγιώτης Ανδρέου

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

ΕΠΛ232 Προγραμματιστικές Τεχνικές και Εργαλεία Δείκτες και Συναρτήσεις (Κεφάλαιο 11, KNK-2ED)

Ορισμός μεταβλητών δεικτών και αρχικοποίηση

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

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

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

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

Ηβασικήσυνάρτηση προγράμματος main()

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

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

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

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

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

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

Λύσεις για τις ασκήσεις του lab5

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

Διάλεξη 5η: Εντολές Επανάληψης

Γλώσσα Προγραμματισμού C

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

Sheet2 Α.Μ FAIL. οριακό PASS. - Έπρεπε να χρησιµοποιήσετε συναρτήσεις από τη string.h

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

Κεφάλαιο 8.7. Πίνακες & Συναρτήσεις ( ιάλεξη 17) ιδάσκων: ηµήτρης Ζεϊναλιπούρ

ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΜΑΘΗΜΑ 3 Ο. Σταθερές-Παράμετροι-Μεταβλητές Αριθμητικοί & Λογικοί Τελεστές Δομή ελέγχου-επιλογής Σύνθετοι έλεγχοι

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

Επανάληψη για τις Τελικές εξετάσεις

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

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

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

Εργαστήριο 1: Επανάληψη Βασικών Εννοιών στη Γλώσσα C

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

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

Κεφάλαιο Πίνακες Ι. (Διάλεξη 16)

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

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

Γλώσσες Προγραμματισμού

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

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

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

Επεξεργασία Αρχείων Κειµένου

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

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

Κεφάλαιο , 3.2: Συναρτήσεις II. (Διάλεξη 12)

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

Α' Εξάμηνο ΕΙΣΑΓΩΓΗ ΣΤΟ ΔΟΜΗΜΕΝΟ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟ. Ερωτήσεις Επανάληψης

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Κλάσεις και Αντικείμενα Αναφορές

Ηλεκτρονικοί Υπολογιστές

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

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

Κεφάλαιο , 3.2: Συναρτήσεις II. ( ιάλεξη 12) ιδάσκων: ηµήτρης Ζεϊναλιπούρ

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

Εισαγωγή στον δομημένο προγραμματισμό

Εργαστήριο 9: Αρχεία

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

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

Transcript:

Δείκτες στην C (επανάληψη) Γλώσσα C & Unix Τμήμα Πληροφορικής, ΑΠΘ B εξάμηνο lpis.csd.auth.gr/curriculum/c+unix/uncl202.html

Εισαγωγή Ένας δείκτης είναι μια μεταβλητή που περιέχει μια διεύθυνση μνήμης. Συνήθως αυτή η διεύθυνση ανήκει σε κάποια άλλη μεταβλητή. Η 1η μεταβλητή «δείχνει» την 2η μεταβλητή. 2

Μια μεταβλητή δείχνει σε κάποια άλλη Διεύθυνση Μνήμης Περιεχόμε να 1000 1004 1001 1002 1003 1004 'a' 1005... 3

Δήλωση Δείκτη Οι δείκτες πρέπει να δηλώνονται πριν χρησιμοποιηθούν. Η δήλωση ενός δείκτη αποτελείται από το σύμβολο * και το όνομά του: τύπος *όνομα Ο τύπος του δείκτη καθορίζει το είδος των μεταβλητών στο οποίο μπορεί να δείχνει. Π.χ. int *ip Αυτό που δείχνει η ip είναι ακέραιος Η έκφραση *ip είναι τύπου int 4

Τελεστές Δεικτών & και * Τελεστής & Μοναδιαίος τελεστής (μόνο ένας τελεστέος) Επιστρέφει τη διεύθυνση μνήμης του τελεστέου Η διεύθυνση μνήμης της μεταβλητής. Τελεστής * Συμπληρωματικός του & Μοναδιαίος τελεστής Επιστρέφει την τιμή της μεταβλητής που είναι αποθηκευμένη στη διεύθυνση μνήμης του τελεστέου Η τιμή στην διεύθυνση μνήμης.... 5

Παράδειγμα Τελεστών Δεικτών void main(void) { int q, count, *m; count= 100; m = &count q = *m; Ο δείκτης m περιέχει τη διεύθυνση μνήμης της count. Καθορίζει τη θέση της τιμής της count μέσα στην μνήμη Όχι την ίδια την τιμή της count Η μεταβλητή q θα περιέχει την τιμή της μεταβλητής count (100) 6

Απόδοση τιμής σε δείκτες Οι δείκτες μπορούν να χρησιμοποιηθούν τόσο στο δεξιό όσο και στο αριστερό μέλος μιας εντολής απόδοσης. #include <stdio.h> void main(void) { int x; int *p1, *p2; Οι δείκτες p1, p2 περιέχουν τη διεύθυνση της μεταβλητής x p1 = &x; p2 = p1; printf( Διεύθυνση p1:%p και p2:%p,p1,p2); 7

Αριθμητική δεικτών Επιτρέπονται μόνο 2 αριθμητικές πράξεις: πρόσθεση, αφαίρεση Έστω ο δείκτης p1 με τιμή 2000 Δείχνει στη διεύθυνση μνήμης 2000 Οι ακέραιοι καταλαμβάνουν 4 bytes. Αν γράψουμε p1++, τότε το περιεχόμενο του p1 γίνεται 2004, όχι 2001! Κάθε φορά που αυξάνεται ο p1, δείχνει στον επόμενο ακέραιο. Το ίδιο ισχύει και για τις μειώσεις. Π.χ. p1 - κάνει την τιμή του δείκτη να έχει τιμή 1996. Γενικά, κάθε φορά που ένας δείκτης: Αυξάνεται κατά 1 δείχνει στην θέση μνήμης του επόμενου στοιχείου του βασικού του τύπου. Μειώνεται κατά 1 δείχνει στην θέση μνήμης του προηγούμενου στοιχείου του βασικού του τύπου. 8

Αριθμητική δεικτών - Παράδειγμα #include <stdio.h> void main() { int x, *p1; p1 is 1245064 (after ++) p1 is 1245068 (after --) p1 is 1245064 x = 5; p1 = &x; printf("p1 is %d\n",p1); p1++; printf("(after ++) p1 is %d\n",p1); p1--; printf("(after --) p1 is %d\n",p1); getchar(); 9

Αριθμητική δεικτών p = p + 9 Ο δείκτης p δείχνει στο 9ο στοιχείο του βασικού τύπου του δείκτη που ακολουθεί από το σημείο στο οποίο έδειχνε. Αφαίρεση ενός δείκτη από έναν άλλο. Συνήθως έχει νόημα όταν οι 2 δείκτες αναφέρονται σε κάποιο κοινό αντικείμενο (π.χ. σε πίνακα) Η αφαίρεση δίνει ως αποτέλεσμα τον αριθμό των στοιχείων μεταξύ των δύο τιμών των δεικτών. Σύγκριση δεικτών Π.χ. p < q Τα p, q αναφέρονται σε πίνακα 10

Αριθμητική δεικτών Δεν επιτρέπονται: Πρόσθεση δεικτών Πρόσθεση-αφαίρεση πραγματικών αριθμών από δείκτες 11

Δείκτες και Πέρασμα Παραμέτρων σε Συναρτήσεις Όταν καλούμε μια συνάρτηση από το κυρίως πρόγραμμα με μεταβλητές ως παραμέτρους, τότε αντιγράφεται η τιμή τους μέσα στην συνάρτηση Δεν μπορούμε να αλλάξουμε τις ίδιες τις μεταβλητές που περιείχαν τις τιμές αυτές. Αυτό το είδος κλήσης συνάρτησης ονομάζεται κλήση με τιμή. 12

Παράδειγμα swap Κλήση με τιμή void swap1(int x, int y) { int temp; temp = x; x = y; y = temp; Η συνάρτηση swap1 δέχεται ως παραμέτρους 2 ακέραιες τιμές και τις αντιμεταθέτει. Αυτό όμως γίνεται τοπικά μέσα στην συνάρτηση και δεν έχει νόημα έξω από αυτήν, αφού όπως έχουμε πει, οι τυπικές παράμετροι μιας συνάρτησης έχουν εμβέλεια μέσα στην ίδια την συνάρτηση. 13

Κλήση με αναφορά Με τη χρήση των δεικτών μπορούμε να περνάμε σε μια συνάρτηση τις διευθύνσεις μνήμης των μεταβλητών αντί για τις ίδιες τις μεταβλητές. Έτσι μπορούμε να αλλάξουμε το περιεχόμενο της διεύθυνσης μνήμης που μας δίνεται σαν παράμετρος και με αυτόν τον τρόπο να αλλάξει η τιμή της μεταβλητής που δόθηκε ως παράμετρος. Αυτό το είδος περάσματος παραμέτρων σε μια συνάρτηση λέγεται κλήση με αναφορά. 14

Παράδειγμα swap Κλήση με αναφορά void swap2(int *x, int *y) { int temp; temp = *x; *x = *y; *y = temp; Αφού τελειώσει η συνάρτηση οι αλλαγές των τιμών των μεταβλητών θα διατηρηθούν, επειδή έγιναν πάνω στις ίδιες τις μεταβλητές και όχι σε ένα αντίγραφο τους, όπως στην κλήση με τιμή. Η συνάρτηση swap2 αντιμεταθέτει τις τιμές που περιέχονται στις διευθύνσεις μνήμης που της δίνονται ως παράμετροι. 15

Κυρίως πρόγραμμα #include <stdio.h> void swap(int *x, int *y); void main (void) { int a, b; a = 10; b = 20; swap1(a, b); printf( swap 1-a:%d,b:%d,a,b); swap2(&a,&b); printf( \nswap 2-a:%d,b:%d,a,b); Κατά την κλήση με τιμή δίνονται οι τιμές των μεταβλητών. Κατά την κλήση με αναφορά θα πρέπει να δοθούν οι διευθύνσεις των μεταβλητών, των οποίων οι τιμές θέλουμε να αλλάξουν. 16

Δείκτες και Πίνακες Η σχέση μεταξύ πινάκων και δεικτών είναι πολύ στενή. Το όνομα ενός πίνακα είναι στην ουσία ένας δείκτης στο 1ο στοιχείο του πίνακα. Π.χ. πίνακας χαρακτήρων p[10] Η διεύθυνση μνήμης του πρώτου στοιχείου του μπορεί να δοθεί είτε ως &p[0], είτε ως p. Η έκφραση (p == &p[0]) είναι αληθής. 17

Δείκτες και Πίνακες Τα στοιχεία των πινάκων είναι ίδιου τύπου και αποθηκεύονται συνεχόμενα στη μνήμη του υπολογιστή. Μπορούμε να χρησιμοποιούμε με ισοδύναμο τρόπο τις εκφράσεις &p[i] και p+i p[i] και *(p+i) int *p, i[10]; p = i; p[5] = 100; *(p+5) = 100; Ισοδύναμες εκφράσεις 18

Διαχείριση στοιχείων πίνακα Η C παρέχει 2 μεθόδους για τη διαχείριση στοιχείων πινάκων. Μέσω της αριθμητικής δεικτών Μέσω του αύξοντα αριθμού των στοιχείων του πίνακα Πότε θα πρέπει να χρησιμοποιείται η μία μέθοδος και πότε η άλλη; Κριτήριο για την επιλογή αποτελεί η ταχύτητα λειτουργίας του προγράμματος. 19

Διαχείριση στοιχείων πίνακα Όταν τα στοιχεία του πίνακα προσπελαύνονται αυστηρώς σειριακά (αύξουσα-φθίνουσα σειρά), τότε η χρήση αριθμητικής δεικτών είναι πιο γρήγορη Όταν τα στοιχεία του πίνακα προσπελαύνονται τυχαία, τότε η χρήση του αύξοντος αριθμού στοιχείου στον πίνακα έχει την ίδια απόδοση με την χρήση αριθμητικής δεικτών Κοστίζει περίπου τον ίδιο χρόνο με τον υπολογισμό μιας σύνθετης έκφρασης με δείκτη. 20

Παράδειγμα - Εκτύπωση string for (t= 0; s[t]!= '\0'; t++) putch(s[t]); while (*s!= \0 ) putch(*s++); Η 2η υλοποίηση είναι πιο γρήγορη και στην πραγματικότητα έτσι υλοποιούνται τέτοιου είδους συναρτήσεις. 21

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

Πέρασμα Πινάκων σε Συναρτήσεις Παράδειγμα void main(void) { int p[10];... func(p); Περνάμε ως παράμετρο στην συνάρτηση func την διεύθυνση του πρώτου στοιχείου του πίνακα p. 23

Ορισμός τυπικής παραμέτρου πίνακα Η συνάρτηση που δέχεται τον πίνακα ως παράμετρο μπορεί να τον δηλώσει ως δείκτη πίνακα με μέγεθος πίνακα χωρίς μέγεθος 24

Ορισμός τυπικής παραμέτρου πίνακα - Παράδειγμα void func1(int *a) {.. void func3(int a[]) {.... void func2(int a[10]) {... Όλοι οι τρόποι κωδικοποίησης της συνάρτησης είναι αποδεκτοί Λένε στον compiler, ότι η συνάρτηση περιμένει μια διεύθυνση μνήμης προς ακέραιο αριθμό 25

Πέρασμα Πινάκων σε Συναρτήσεις Αφού περνάμε μια διεύθυνση μνήμης σαν παράμετρο σε μια συνάρτηση, σημαίνει ότι κάνουμε κλήση με αναφορά. Αν αλλάξουμε το περιεχόμενο των στοιχείων αυτού του πίνακα μέσα στην συνάρτηση, οι αλλαγές θα είναι μόνιμες. Η συνάρτηση δεν μπορεί να ξέρει το μέγεθος του πίνακα. Δέχεται μόνο τη διεύθυνση του 1ου στοιχείου του πίνακα. Πρέπει εμείς να περνάμε ως παράμετρο και το μέγεθος του πίνακα. 26

Πέρασμα Πινάκων σε Συναρτήσεις - Παράδειγμα void reverse(int *pinakas, int mikos) { int i,temp; for (i = 0; i < (mikos / 2); i++) { temp = pinakas[i]; pinakas[i] = pinakas[mikos-1-i]; pinakas[mikos-1-i] = temp; Περνάμε ως παράμετρο στη reverse τη διεύθυνση και το μέγεθος ενός πίνακα αριθμών και αντιστρέφει τα στοιχεία του void main(void) { int i, a[] = {1,2,3,4,5; int size = sizeof(a)/sizeof(a[0]); reverse(a,size); for (i = 0; i < size; i++) printf( %2d,a[i]); Τελικά θα τυπωθούν τα στοιχεία του πίνακα με την ανάποδη σειρά. 27

Προβλήματα με Δείκτες Όταν ένας δείκτης περιέχει λάθος τιμή, είναι ένα από τα δυσκολότερα λάθη για να εντοπιστεί Το πρόβλημα είναι ότι κάθε φορά που διαβάζεται ή γράφεται η περιοχή μνήμης που δείχνει, αυτό γίνεται σε μια άγνωστη περιοχή της μνήμης. Στην ανάγνωση το κακό είναι μικρό, αφού απλά διαβάζονται σκουπίδια. Στην εγγραφή, μπορεί να «καταστρέφονται» (γράφοντας από πάνω) άλλα τμήματα του κώδικα ή των μεταβλητών. Αυτό μπορεί να εμφανιστεί σαν λάθος κατά την εκτέλεση του προγράμματος αργότερα από το σημείο που γίνεται. Έτσι μπορεί να αναζητείται το πρόβλημα σε λάθος σημείο, αφού τίποτα δεν θα υποδεικνύει ότι το πρόβλημα είναι στον δείκτη. 28

Λάθος μη-αρχικοποίησης void main(void) { int x, *p; Χρήση ενός δείκτη που δεν έχει αρχικοποιηθεί. x = 10; *p = x; Αναθέτουμε την τιμή 10 σε μια άγνωστη θέση στη μνήμη, αφού ο δείκτης p, δεν έχει αρχικοποιηθεί σε κάποια θέση μνήμης 29

Λάθος ανάθεσης void main(void) { int x, *p; x = 10; p = x; Κατά λάθος ανάθεση σε ένα δείκτη μιας τιμής, αντί μίας διεύθυνσης μνήμης 30

Πίνακες Δεικτών Παράδειγμα Ταξινόμηση μιας ομάδας γραμμών κειμένου με αλφαβητική σειρά Απλουστευμένη εκδοχή της sort του Unix Οι γραμμές κειμένου έχουν διαφορετικά μήκη μεταξύ τους Δεν μπορούν να συγκριθούν ή να μεταφερθούν με μία μόνο ενέργεια 31

Ταξινόμηση γραμμών κειμένου Οι γραμμές που πρέπει να ταξινομηθούν είναι αποθηκευμένες «κολλητά» η μία μετά την άλλη σε έναν μεγάλο πίνακα χαρακτήρων Κάθε γραμμή μπορεί να προσπελαστεί με ένα δείκτη στον πρώτο χαρακτήρα της Οι δείκτες αποθηκεύονται σε πίνακα Αντί να εναλλαχθούν οι γραμμές κειμένου, εναλλάσσονται οι δείκτες του πίνακα 32

Ταξινόμηση γραμμών κειμένου Πλεονεκτήματα: Δεν υπάρχει περίπλοκη διαχείριση της μνήμης Δε χρονοτριβεί το πρόγραμμα από την μετακίνηση των γραμμών Διαδικασία: Διάβασε όλες τις γραμμές εισόδου Ταξινόμησέ τις Τύπωσέ τις ταξινομημένες 33

Κύριο Πρόγραμμα #include <stdio.h> #include <string.h> #define MAXLINES 5000 // Μέγιστος αριθμός γραμμών char *lineptr[maxlines]; // Πίνακας δεικτών σε γραμμές main() { int nlines; // Αριθμός διαβασμένων γραμμών if ((nlines = readlines(lineptr, MAXLINES)) >= 0) { sort(lineptr, nlines); Ταξινόμησε writelines(lineptr, nlines); τις return 0; Τύπωσε γραμμές Διάβασε τις τις γραμμές else { printf("error: input too big to sort\n"); return 1; 34

Συνάρτηση ανάγνωσης γραμμών readlines #define MAXLEN 1000 // Μέγιστο μήκος γραμμής int readlines(char *lineptr[], int maxlines) { int len, nlines; Διαβάζει γραμμή char *p, line[maxlen]; nlines = 0; while ((len = getline(line, MAXLEN)) > 0) if (nlines >= maxlines p = alloc(len) == NULL) return -1; Σταματάει σε μηδενική γραμμή else { Σβήνει το newline line[len-1] = '\0'; Αντιγράφει την γραμμή strcpy(p,line); στο χώρο που δεσμεύθηκε lineptr[nlines++] = p; Δέσμευσε Εάν πολλές χώρο γραμμές στη μνήμη Βάλε τον για pointer επέστρεψε την γραμμή στον πίνακα error return nlines; Πάνε στην Εάν επόμενη δεν χωράει θέση/γραμμή επέστρεψε Επέστρεψε τον αριθμό γραμμών που error διαβάστηκαν 35

Συνάρτηση ανάγνωσης 1 γραμμής getline // Διαβάζει γραμμή στο s, Επιστρέφει μήκος γραμμής int getline(char s[],int lim) { int c, i; for (i=0; i<lim-1 && (c=getchar())!=eof && c! ='\n'; s[i] = c; if (c == '\n') { s[i] = c; ++i; s[i] = '\0'; return i; 36 ++i) Διαβάζει χαρακτήρα Τερματισμός string και Σταματάει επιστροφή στο μήκους τέλος αρχείου (CTRL-Z), Το ENTER συμπεριλαμβάνεται στο ENTER και σε μεγάλη στο string γραμμή

Συνάρτηση δέσμευσης μνήμης alloc #define ALLOCSIZE 10000 // διαθέσιμη μνήμη static char allocbuf[allocsize]; // αποθήκη // επόμενη ελεύθερη θέση static char *allocp = allocbuf; // επιστροφή δείκτη σε n χαρακτήρες char *alloc(int n) { if (allocbuf+allocsize-allocp>=n) { allocp += n; Επόμενη ελεύθερη θέση return allocp - n; Επέστρεψε τον παλιό δείκτη else return 0; Χωράει? Δεν υπάρχει χώρος Επέστρεψε 0 37

Πώς δουλεύει η alloc 38

Συνάρτηση εκτύπωσης γραμμών writelines void writelines(char *lineptr[], int nlines) { int i; for (i = 0; i < nlines; i++) Εναλλακτικά printf("%s\n", lineptr[i]); void writelines(char *lineptr[], int nlines) { while (nlines-- > 0) printf("%s\n", *lineptr++); Τυπώνεται το 1ο string που δείχνει ο πίνακας και μετά πάει στον επόμενο δείκτη/string Η nlines μειώνεται Σταματάμε όταν φτάσει στο 0 39

Ταξινόμηση με επιλογή select sort Ξεκινάμε από το 1ο στοιχείο του πίνακα (εξωτερικός βρόχος) Το συγκρίνουμε με όλα τα υπόλοιπα (εσωτερικός βρόχος) Αν κάποιο είναι μικρότερο, το αντικαθιστά στην 1η θέση Η διαδικασία συνεχίζεται (εσωτερικός βρόχος) για όλα τα στοιχεία του πίνακα Όταν τελειώσει ο εσωτερικός βρόχος η 1η θέση έχει το μικρότερο στοιχείο Συνεχίζουμε την ίδια διαδικασία από τη θέση 2 (εξωτερικός βρόχος), κ.ο.κ. Στο τέλος όλα τα στοιχεία έχουν μπει στην σωστή σειρά 40

Συνάρτηση ταξινόμησης γραμμών με επιλογή (select sort) void sort(char *v[], int n) { int i, j; for(i = 0; i < n - 1; i++) for(j = i + 1; j < n; j++) if (strcmp(v[i],v[j]) > 0) swap(v, i, j); 41

Ανταλλαγή δυο στοιχείων (δεικτών) του πίνακα void swap(char *v[], int i, int j) { char *temp; temp = v[i]; v[i] = v[j]; v[j] = temp; Κάθε στοιχείο του πίνακα είναι δείκτης σε χαρακτήρα (string) 42

Άσκηση 5.7 Ξαναγράψτε την readlines ώστε να αποθηκεύει τις γραμμές σε ένα πίνακα που δίνεται από την main, αντί να καλεί την alloc για να της παραχωρεί μνήμη. Σε τι διαφέρει από το προηγούμενο πρόγραμμα? 43

Εναλλακτική readlines char lines[maxlines][maxlen]; main() {... Πίνακας 2 διαστάσεων if ((nlines = readlines2(lines, MAXLINES)) >= 0) {... int readlines2(char lines[][maxlen], int maxlines) { int len, nlines = 0; while ((len = getline(lines[nlines], MAXLEN)) > 0) if (nlines >= maxlines) return -1; else { lineptr[nlines] = lines[nlines]; lines[nlines++][len - 1] = '\0'; return nlines; Σύνδεση με τον πίνακα 44δεικτών Ανάγνωση κατευθείαν στη σωστή θέση

Διαφορές των 2 προγραμμάτων Το 2ο πρόγραμμα είναι ταχύτερο γιατί δεν χρησιμοποιεί την strcpy για να αντιγράψει τη γραμμή που διαβάστηκε στον ενιαίο χώρο στη μνήμη που δεσμεύει η alloc Το 2ο πρόγραμμα σπαταλάει πολύ μνήμη γιατί ο πίνακας 2 διαστάσεων καταλαμβάνει πάντα τον ίδιο χώρο στη μνήμη, άσχετα με το αν οι γραμμές τον χρησιμοποιούν ή όχι 45

Σπατάλη χώρου μνήμης h e l l o \0 w o r l d \0 T h i s i s \0 a n \0 e x a m l e \0................................................... 46

Οικονομία χώρου μνήμης......... h e l l o \0 w o r l d \0 T h i s i s \0...... 47