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

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

description

Δείκτες στην C ( επανάληψη ). Γλώσσα C & Unix Τμήμα Πληροφορικής, ΑΠΘ B’ εξάμηνο. lpis . csd . auth . gr / curriculum / C + Unix / UNCL 202. html. Εισαγωγή. Ένας δείκτης είναι μια μεταβλητή που περιέχει μια διεύθυνση μνήμης. Συνήθως αυτή η διεύθυνση ανήκει σε κάποια άλλη μεταβλητή. - PowerPoint PPT Presentation

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

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

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

Γλώσσα C & UnixΤμήμα Πληροφορικής, ΑΠΘB’ εξάμηνο

lpis.csd.auth.gr/curriculum/C+Unix/UNCL202.html

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

2

Εισαγωγή

Ένας δείκτης είναι μια μεταβλητή που περιέχει μια διεύθυνση μνήμης.

Συνήθως αυτή η διεύθυνση ανήκει σε κάποια άλλη μεταβλητή.

Η 1η μεταβλητή «δείχνει» την 2η μεταβλητή.

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

3

Μια μεταβλητή δείχνει σε κάποια άλλη

Διεύθυνση Μνήμης

Περιεχόμενα

1000 1004

1001

1002

1003

1004 'a'

1005

.

.

.

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

4

Δήλωση Δείκτη

Οι δείκτες πρέπει να δηλώνονται πριν χρησιμοποιηθούν.

Η δήλωση ενός δείκτη αποτελείται από το σύμβολο * και το όνομά του:

τύπος *όνομα Ο τύπος του δείκτη καθορίζει το είδος των

μεταβλητών στο οποίο μπορεί να δείχνει. Π.χ. int *ip

Αυτό που δείχνει η ip είναι ακέραιος Η έκφραση *ip είναι τύπου int

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

5

Τελεστές Δεικτών & και *

Τελεστής & Μοναδιαίος τελεστής (μόνο ένας τελεστέος) Επιστρέφει τη διεύθυνση μνήμης του τελεστέου “Η διεύθυνση μνήμης της μεταβλητής …”.

Τελεστής * Συμπληρωματικός του & Μοναδιαίος τελεστής Επιστρέφει την τιμή της μεταβλητής που είναι

αποθηκευμένη στη διεύθυνση μνήμης του τελεστέου

“Η τιμή στην διεύθυνση μνήμης ...”.

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

6

Παράδειγμα Τελεστών Δεικτών

void main(void){ int q, count, *m;

count= 100; m = &count q = *m;}

Ο δείκτης m περιέχει τη διεύθυνση μνήμης της count.

Καθορίζει τη θέση της τιμής της count μέσα στην μνήμη

Όχι την ίδια την τιμή της count

Η μεταβλητή q θα περιέχει την τιμή της μεταβλητής count (100)

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

7

Απόδοση τιμής σε δείκτες Οι δείκτες μπορούν να χρησιμοποιηθούν τόσο στο

δεξιό όσο και στο αριστερό μέλος μιας εντολής απόδοσης.

#include <stdio.h>

void main(void){ int x; int *p1, *p2;

p1 = &x; p2 = p1;

printf(“Διεύθυνση p1:%p και p2:%p”,p1,p2);}

• Οι δείκτες p1, p2 περιέχουν τη διεύθυνση της μεταβλητής x

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

8

Αριθμητική δεικτών Επιτρέπονται μόνο 2 αριθμητικές πράξεις: πρόσθεση,

αφαίρεση Έστω ο δείκτης p1 με τιμή 2000

Δείχνει στη διεύθυνση μνήμης 2000 Οι ακέραιοι καταλαμβάνουν 4 bytes.

Αν γράψουμε p1++, τότε το περιεχόμενο του p1 γίνεται 2004, όχι 2001!

Κάθε φορά που αυξάνεται ο p1, δείχνει στον επόμενο ακέραιο. Το ίδιο ισχύει και για τις μειώσεις.

Π.χ. p1–- κάνει την τιμή του δείκτη να έχει τιμή 1996. Γενικά, κάθε φορά που ένας δείκτης:

Αυξάνεται κατά 1 δείχνει στην θέση μνήμης του επόμενου στοιχείου του βασικού του τύπου.

Μειώνεται κατά 1 δείχνει στην θέση μνήμης του προηγούμενου στοιχείου του βασικού του τύπου.

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

9

Αριθμητική δεικτών - Παράδειγμα

#include <stdio.h>

void main(){

int x, *p1;

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();}

p1 is 1245064(after ++) p1 is 1245068(after --) p1 is 1245064

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

10

Αριθμητική δεικτών p = p + 9

Ο δείκτης p δείχνει στο 9ο στοιχείο του βασικού τύπου του δείκτη που ακολουθεί από το σημείο στο οποίο έδειχνε.

Αφαίρεση ενός δείκτη από έναν άλλο. Συνήθως έχει νόημα όταν οι 2 δείκτες

αναφέρονται σε κάποιο κοινό αντικείμενο (π.χ. σε πίνακα)

Η αφαίρεση δίνει ως αποτέλεσμα τον αριθμό των στοιχείων μεταξύ των δύο τιμών των δεικτών.

Σύγκριση δεικτών Π.χ. p < q Τα p, q αναφέρονται σε πίνακα

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

11

Αριθμητική δεικτών

Δεν επιτρέπονται: Πρόσθεση δεικτών

Πρόσθεση-αφαίρεση πραγματικών αριθμών από δείκτες

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

12

Δείκτες και Πέρασμα Παραμέτρων σε Συναρτήσεις

Όταν καλούμε μια συνάρτηση από το κυρίως πρόγραμμα με μεταβλητές ως παραμέτρους, τότε αντιγράφεται η τιμή τους μέσα στην συνάρτηση

Δεν μπορούμε να αλλάξουμε τις ίδιες τις μεταβλητές που περιείχαν τις τιμές αυτές.

Αυτό το είδος κλήσης συνάρτησης ονομάζεται “κλήση με τιμή”.

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

13

Παράδειγμα swap – Κλήση με τιμή

void swap1(int x, int y){ int temp;

temp = x; x = y; y = temp;}

• Η συνάρτηση swap1 δέχεται ως παραμέ-τρους 2 ακέραιες τιμές και τις αντιμεταθέτει.

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

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

14

Κλήση με αναφορά

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

Έτσι μπορούμε να αλλάξουμε το περιεχόμενο της διεύθυνσης μνήμης που μας δίνεται σαν παράμετρος και με αυτόν τον τρόπο να αλλάξει η τιμή της μεταβλητής που δόθηκε ως παράμετρος.

Αυτό το είδος περάσματος παραμέτρων σε μια συνάρτηση λέγεται “κλήση με αναφορά”.

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

15

Παράδειγμα swap – Κλήση με αναφορά

void swap2(int *x, int *y){ int temp;

temp = *x; *x = *y; *y = temp;}

• Αφού τελειώσει η συνάρτηση οι αλλαγές των τιμών των μεταβλητών θα διατηρηθούν, επειδή έγιναν πάνω στις ίδιες τις μεταβλητές και όχι σε ένα αντίγραφο τους, όπως στην “κλήση με τιμή”.

• Η συνάρτηση swap2 αντιμεταθέτει τις τιμές που περιέχονται στις διευθύνσεις μνήμης που της δίνονται ως παράμετροι.

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

16

Κυρίως πρόγραμμα#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);}

• Κατά την κλήση με αναφορά θα πρέπει να δοθούν οι διευθύνσεις των μεταβλητών, των οποίων οι τιμές θέλουμε να αλλάξουν.

• Κατά την κλήση με τιμή δίνονται οι τιμές των μεταβλητών.

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

17

Δείκτες και Πίνακες

Η σχέση μεταξύ πινάκων και δεικτών είναι πολύ στενή.

Το όνομα ενός πίνακα είναι στην ουσία ένας δείκτης στο 1ο στοιχείο του πίνακα.

Π.χ. πίνακας χαρακτήρων p[10] Η διεύθυνση μνήμης του πρώτου

στοιχείου του μπορεί να δοθεί είτε ως &p[0], είτε ως p.

Η έκφραση (p == &p[0]) είναι αληθής.

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

18

Δείκτες και Πίνακες

Τα στοιχεία των πινάκων είναι ίδιου τύπου και αποθηκεύονται συνεχόμενα στη μνήμη του υπολογιστή.

Μπορούμε να χρησιμοποιούμε με ισοδύναμο τρόπο τις εκφράσεις &p[i] και p+i p[i] και *(p+i)

int *p, i[10];

p = i; p[5] = 100;*(p+5) = 100;

• Ισοδύναμες εκφράσεις

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

19

Διαχείριση στοιχείων πίνακα

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

στοιχείων του πίνακα Πότε θα πρέπει να χρησιμοποιείται

η μία μέθοδος και πότε η άλλη; Κριτήριο για την επιλογή αποτελεί

η ταχύτητα λειτουργίας του προγράμματος.

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

20

Διαχείριση στοιχείων πίνακα

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

Όταν τα στοιχεία του πίνακα προσπελαύνονται τυχαία, τότε η χρήση του αύξοντος αριθμού στοιχείου στον πίνακα έχει την ίδια απόδοση με την χρήση αριθμητικής δεικτών Κοστίζει περίπου τον ίδιο χρόνο με τον

υπολογισμό μιας σύνθετης έκφρασης με δείκτη.

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

21

Παράδειγμα - Εκτύπωση string

for (t= 0; s[t] != '\0'; t++)

putch(s[t]);

while (*s != ’\0’)

putch(*s++);

•Η 2η υλοποίηση είναι πιο γρήγορη και

στην πραγματικότητα έτσι υλοποιούνται

τέτοιου είδους συναρτήσεις.

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

22

Πέρασμα Πινάκων σε Συναρτήσεις

Στη C δεν γίνεται να περαστούν τα περιεχόμενα ενός ολόκληρου πίνακα ως παράμετρος σε μια συνάρτηση.

Αυτό που μπορεί να περαστεί στη συνάρτηση είναι η διεύθυνση μνήμης του πρώτου στοιχείου του πίνακα Το όνομά του.

Δίνουμε το όνομα του πίνακα ως παράμετρο κατά την κλήση μιας συνάρτησης.

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

23

Πέρασμα Πινάκων σε Συναρτήσεις Παράδειγμα

void main(void){ int p[10]; . . . func(p);}

• Περνάμε ως παράμετρο στην

συνάρτηση func την διεύθυνση του

πρώτου στοιχείου του πίνακα p.

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

24

Ορισμός τυπικής παραμέτρου πίνακα

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

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

25

Ορισμός τυπικής παραμέτρου πίνακα - Παράδειγμα

void func1(int *a){ . . .}

void func2(int a[10]){ . . .}

void func3(int a[]){ . . .}

Όλοι οι τρόποι κωδικοποίησης της συνάρτησης

είναι αποδεκτοί

Λένε στον compiler, ότι η συνάρτηση περιμένει

μια διεύθυνση μνήμης προς ακέραιο αριθμό

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

26

Πέρασμα Πινάκων σε Συναρτήσεις

Αφού περνάμε μια διεύθυνση μνήμης σαν παράμετρο σε μια συνάρτηση, σημαίνει ότι κάνουμε “κλήση με αναφορά”. Αν αλλάξουμε το περιεχόμενο των στοιχείων

αυτού του πίνακα μέσα στην συνάρτηση, οι αλλαγές θα είναι μόνιμες.

Η συνάρτηση δεν μπορεί να ξέρει το μέγεθος του πίνακα. Δέχεται μόνο τη διεύθυνση του 1ου στοιχείου

του πίνακα. Πρέπει εμείς να περνάμε ως παράμετρο και το

μέγεθος του πίνακα.

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

27

Πέρασμα Πινάκων σε Συναρτήσεις - Παράδειγμα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; }}

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]);}

Περνάμε ως παράμετρο στη reverse τη διεύθυνση και το μέγεθος ενός πίνακα αριθμών και αντιστρέφει τα στοιχεία του

Τελικά θα τυπωθούν τα στοιχεία του πίνακα με την ανάποδη σειρά.

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

28

Προβλήματα με Δείκτες Όταν ένας δείκτης περιέχει λάθος τιμή, είναι ένα από

τα δυσκολότερα λάθη για να εντοπιστεί Το πρόβλημα είναι ότι κάθε φορά που διαβάζεται ή

γράφεται η περιοχή μνήμης που δείχνει, αυτό γίνεται σε μια άγνωστη περιοχή της μνήμης. Στην ανάγνωση το κακό είναι μικρό, αφού απλά

διαβάζονται σκουπίδια. Στην εγγραφή, μπορεί να «καταστρέφονται» (γράφοντας

από πάνω) άλλα τμήματα του κώδικα ή των μεταβλητών. Αυτό μπορεί να εμφανιστεί σαν λάθος κατά την εκτέλεση

του προγράμματος αργότερα από το σημείο που γίνεται. Έτσι μπορεί να αναζητείται το πρόβλημα σε λάθος

σημείο, αφού τίποτα δεν θα υποδεικνύει ότι το πρόβλημα είναι στον δείκτη.

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

29

Λάθος μη-αρχικοποίησης

void main(void){ int x, *p;

x = 10; *p = x;}

Χρήση ενός δείκτη που δεν έχει αρχικοποιηθεί.

Αναθέτουμε την τιμή 10

σε μια άγνωστη θέση στη

μνήμη, αφού ο δείκτης p,

δεν έχει αρχικοποιηθεί σε

κάποια θέση μνήμης

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

30

Λάθος ανάθεσης

void main(void){ int x, *p;

x = 10; p = x;}

Κατά λάθος ανάθεση σε

ένα δείκτη μιας τιμής,

αντί μίας διεύθυνσης

μνήμης

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

31

Πίνακες Δεικτών – Παράδειγμα

Ταξινόμηση μιας ομάδας γραμμών κειμένου με αλφαβητική σειρά

Απλουστευμένη εκδοχή της sort του Unix

Οι γραμμές κειμένου έχουν διαφορετικά μήκη μεταξύ τους

Δεν μπορούν να συγκριθούν ή να μεταφερθούν με μία μόνο ενέργεια

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

32

Ταξινόμηση γραμμών κειμένου

Οι γραμμές που πρέπει να ταξινομηθούν είναι αποθηκευμένες «κολλητά» η μία μετά την άλλη σε έναν μεγάλο πίνακα χαρακτήρων

Κάθε γραμμή μπορεί να προσπελαστεί με ένα δείκτη στον πρώτο χαρακτήρα της

Οι δείκτες αποθηκεύονται σε πίνακα Αντί να εναλλαχθούν οι γραμμές κειμένου,

εναλλάσσονται οι δείκτες του πίνακα

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

33

Ταξινόμηση γραμμών κειμένου

Πλεονεκτήματα: Δεν υπάρχει περίπλοκη διαχείριση της

μνήμης Δε χρονοτριβεί το πρόγραμμα από την

μετακίνηση των γραμμών Διαδικασία:

Διάβασε όλες τις γραμμές εισόδου Ταξινόμησέ τις Τύπωσέ τις ταξινομημένες

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

34

Κύριο Πρόγραμμα#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; }}

• Διάβασε τις γραμμές

• Ταξινόμησε τις γραμμές

• Τύπωσε τις γραμμές

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

35

Συνάρτηση ανάγνωσης γραμμών 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 { line[len-1] = '\0'; strcpy(p,line); lineptr[nlines++] = p; } return nlines;}

• Διαβάζει γραμμή

• Σταματάει σε μηδενική γραμμή

• Εάν πολλές γραμμές επέστρεψε error

• Δέσμευσε χώρο στη μνήμη για την γραμμή

• Εάν δεν χωράει επέστρεψε error

• Σβήνει το newline• Αντιγράφει την γραμμή

στο χώρο που δεσμεύθηκε

• Βάλε τον pointer στον πίνακα

• Πάνε στην επόμενη θέση/γραμμή• Επέστρεψε τον αριθμό γραμμών που διαβάστηκαν

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

36

Συνάρτηση ανάγνωσης 1 γραμμής getline

// Διαβάζει γραμμή στο s, Επιστρέφει μήκος γραμμήςint getline(char s[],int lim){ int c, i;

for (i=0; i<lim-1 && (c=getchar())!=EOF && c!='\n';

++i) s[i] = c; if (c == '\n') { s[i] = c; ++i; } s[i] = '\0'; return i;}

• Διαβάζει χαρακτήρα

• Σταματάει στο τέλος αρχείου (CTRL-Z), στο ENTER και σε μεγάλη γραμμή

• Το ENTER συμπεριλαμβάνεται στο string

• Τερματισμός string και επιστροφή μήκους

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

37

Συνάρτηση δέσμευσης μνήμης 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

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

38

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

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

39

Συνάρτηση εκτύπωσης γραμμών 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++);

}

• Η nlines μειώνεται

• Σταματάμε όταν φτάσει στο 0

• Τυπώνεται το 1ο string που δείχνει ο πίνακας και μετά πάει στον επόμενο δείκτη/string

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

40

Ταξινόμηση με επιλογή select sort

Ξεκινάμε από το 1ο στοιχείο του πίνακα (εξωτερικός βρόχος)

Το συγκρίνουμε με όλα τα υπόλοιπα (εσωτερικός βρόχος)

Αν κάποιο είναι μικρότερο, το αντικαθιστά στην 1η θέση

Η διαδικασία συνεχίζεται (εσωτερικός βρόχος) για όλα τα στοιχεία του πίνακα

Όταν τελειώσει ο εσωτερικός βρόχος η 1η θέση έχει το μικρότερο στοιχείο

Συνεχίζουμε την ίδια διαδικασία από τη θέση 2 (εξωτερικός βρόχος), κ.ο.κ.

Στο τέλος όλα τα στοιχεία έχουν μπει στην σωστή σειρά

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

41

Συνάρτηση ταξινόμησης γραμμών με επιλογή (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);

}

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

42

Ανταλλαγή δυο στοιχείων (δεικτών) του πίνακα

void swap(char *v[], int i, int j){ char *temp;

temp = v[i]; v[i] = v[j]; v[j] = temp;}

•Κάθε στοιχείο του πίνακα είναι δείκτης σε χαρακτήρα (string)

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

43

Άσκηση 5.7

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

Σε τι διαφέρει από το προηγούμενο πρόγραμμα?

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

44

Εναλλακτική readlineschar lines[MAXLINES][MAXLEN];main() { ... 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;}

• Πίνακας 2 διαστάσεων

• Ανάγνωση κατευθείαν στη σωστή θέση

• Σύνδεση με τον πίνακα δεικτών

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

45

Διαφορές των 2 προγραμμάτων

Το 2ο πρόγραμμα είναι ταχύτερο γιατί δεν χρησιμοποιεί την strcpy για να αντιγράψει τη γραμμή που διαβάστηκε στον ενιαίο χώρο στη μνήμη που δεσμεύει η alloc

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

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

46

Σπατάλη χώρου μνήμης

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

... ... ... ...

... ... ... ... ...

... ... ... ... ... ...

... ...

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

47

Οικονομία χώρου μνήμης

... ... ...

h e l l o \0 w o r l d \0 T h i s i s \0 ... ...