ΕΠΛ 34: Εισαγωγή στον Προγραμματισμό για ΗΜΥ Αχιλλέας Αχιλλέως, Τμήμα Πληροφορικής, Πανεπιστήμιο Κύπρου Email: achilleas@cs.ucy.ac.cy
Κεφάλαιο 12 Πίνακες εικτών (Pointers Arrays)
Θέματα ιάλεξης Στην ενότητα αυτή θα μελετηθούν τα εξής επιμέρους μρ θέματα: 1. Πίνακες εικτών (Pointers Arrays) 2. Σχέση με Πολυδιάστατους Πίνακες 3. Ορίσματα γραμμής ιαταγών
Πίνακες εικτών (Pointer Arrays) Πίνακες δεικτών είναι πίνακες που περιέχουν δείκτες. ήλωση Πίνακα εικτών γίνεται ως τύπος *όνομα_πίνακα[μέγεθος_πίνακα] π.χ. η δήλωση int *array[1] = { ; λέει ότι ο a είναι πίνακας μεγέθους 1 και τα στοιχεία του είναι δείκτες σε int. Επομένως, στο array[6] φυλάγεται ο δείκτης προς τον ακέραιο και *array[6] είναι ο ακέραιος στον οποίο δείχνει.
Παράδειγμα 1 Αρχικοποίηση τιμής σε πίνακα δεικτών. #include <stdio.h> char *array1[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September","October", "November", "December"; printf("%d\n", array1[2]); printf("%s\n", array1[2]); *array1[1]... Μνήμη January February... November December Oι χαρακτήρες κάθε συμβολοσειράς τοποθετούνται κάπου στη μνήμη και στο name[i] τοποθετείται δείκτης προς αυτούς τους χαρακτήρες.
Παράδειγμα 2 Αρχικοποίηση τιμής σε πίνακα δεικτών. #include <stdio.h> int x =, y = 1, z = 2, k = 3; int *array2[4] = {; array2[] = &x; array2[1] = &y; array2[2] = &z; array2[3] = &k; printf("%d\n", array2[2]); printf("%d\n", *array2[2]); *array2[4] Μνήμη O κάθε ακέραιος τοποθετείται κάπου στη μνήμη και στο a3[i] τοποθετείται δείκτης προς αυτούς τους ακέραιους. 1 2 3
Παράδειγμα 3 Να γράψετε συνάρτηση που, με δεδομένο εισόδου ακέραιο i, επιστρέφει το όνομα του i-οστού μήνα (αν υπάρχει). #include <stdio.h> char *getmonthname(char *array3[], int i){ if (i < 1 i > 11) return array3[]; else return array3[i]; char *array3[] = {"January", "February", "March", "April","May", "June", "July", "August", "September", "October", "November", "December"; printf("%s", getmonthname(array3, 1)); return ;
Σωστή Αρχικοποίηση/Χρήση / #include <stdio.h> char *a1[1]; int i; for (i=;i<1;i++){ #include <stdio.h> char *a2[1] = { ; int j; for (j=;j<1;i++){ j<1 printf("%d\n", a1[i]); => printf("%d\n", a2[j]); => Εκτυπώνει 1628344792 2289544 288999592 288773112-1 28877314 288772914 289866642 28883211 1892 Εκτυπώνει
Σωστή Αρχικοποίηση/Χρήση / #include <stdio.h> char *a3[1] = {; char name[] = "car"; a3[] = name; printf("%s\n", a3[]); => Εκτυπώνει car #include <stdio.h> char *a4[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"; printf("%d\n", a4[2]); printf("%s\n", a4[2]); => Εκτυπώνει 42269 March
Σωστή Αρχικοποίηση Προσοχή: Τον χώρο (π.χ. int) στον οποίο θα δείχνει κάθε pointer a[i], πρέπει να τον δεσμεύσουμε/ ορίσουμε ξεχωριστά (i.e. x, y, z). #include <stdio.h> int *a5[3] = {, 1, 2; printf("%d\n", a5[2]); printf("%d\n",*a5[2]); = > Δημιουργεί compile error! #include <stdio.h> int x =, y = 1, z = 2; int *a6[3] = {; a6[] = &x; a6[1] = &y; a6[2] = &z; printf("%d\n", a6[2]); printf("%d\n", *a6[2]); => Εκτυπώνει 228532 2 #include <stdio.h> double xd =.1, yd =.2, zd =.3; double *a7[3] = {; a7[] = &xd; a7[1] = &yd; a7[2] = &zd; printf("%d\n",a7[2]); printf("%f\n",*a7[2]); => Εκτυπώνει 228488.3
Υπενθύμηση: Πολυδιάστατοι Πίνακες Η C διαθέτει ορθογωνικούς πολυδιάστατους πίνακες. Κατά τη δήλωση ενός πολυδιάστατου πίνακα (όπως και για ένα μονοδιάστατο) δά ) πρέπει να προσδιορίσουμε τις διαστάσεις του. π.χ. char array[3][7] Ένας πολυδιάστατος πίνακας είναι ένας μονοδιάστατος πίνακας κάθε στοιχείο του οποίου είναι ένας πίνακας. Για να αναφερθούμε σε κάποιο στοιχείο του πίνακα χρησιμοποιούμε δείκτες θέσης. π.χ. array[i][j] /*[γραμμή][στήλη]*/
Υπενθύμηση: Πολυδιάστατοι πίνακες (συν.) Αρχικοποίηση Πολυδιάστατου Πίνακα Μια λίστα αρχικών τιμών κλεισμένη σε άγκιστρα, όπου κάθε τιμή παίρνει αρχική τιμή από μια αντίστοιχη υπολίστα, π.χ. int daysofmonth[2][5] = { {, 31, 28, 31, 3, {, 31, 29, 31, 3 Μεταβίβαση ισδιάστατου Πίνακα σε Συνάρτηση Η δήλωση των παραμέτρων της συνάρτησης πρέπει να περιλαμβάνει τον αριθμό των στηλών κάθε δισδιάστατου πίνακα. Ο αριθμός των γραμμών είναι αδιάφορος. Για παράδειγμα, όλες οι πιο κάτω δηλώσεις είναι έγκυρες. foo( int daysofmonth[2][5] ) {... y foo( int daysofmonth[][5] ) {... foo( int (*daysofmonth)[5] ) {...
Πολυδιάστατοι Πίνακες vs. Πίνακες εικτών Έστω int a[1][2]: int *b[1]; Ποια η διαφορά ανάμεσα στους δύο πίνακες; Oaείναι πραγματικά δισδιάστατος πίνακας: κατά τον ορισμό του δεσμεύθηκαν 2 συνεχόμενες θέσεις. Κατά τον ορισμό του b κατανέμεται χώρος για 1 δείκτες. Απόδοση αρχικών τιμών πρέπει να γίνει ρητά είτε στατικά (i.e. { )είτε ί με κώδικα (for loop). int a[1][2]; int *b[1]; printf("%d, %d", sizeof(a), sizeof(b)); Εκτυπώνει 8, 4 -- δηλαδή (1x2x4) και (1x4) Πλεονέκτημα Πίνακα εικτών: Κάθε δί δείκτης μπορεί να δείχνει σε γραμμή με διαφορετικό μήκος.
Παράδειγμα Έστω char fixed[] [15] = { Illegal month, Jan, Feb, March char *variable[] = { Illegal month, Jan, Feb, March Γραφικά στο επίπεδο της μνήμης έχουμε Illegal month\--- Jan\------------ Feb\------------ Μarch\--------- 15 3 45 Fixed length! Ο χαρακτήρας - συμβολίζει ένα αχρησιμοποίητο byte Illegal month\ Jan\ Feb\ Variable length! Μarch\
Παράμετροι της συνάρτησης main() H συνάρτηση main με παράμετρο void θέλοντας να δείξουμε ότι η συνάρτηση main δε δέχεται ορίσματα. int main(void) {... Αυτό όμως δε σημαίνει ότι δεν μπορούμε μ να περάσουμε ορίσματα. Τα δυνατά ορίσματα όμως της main είναι καθορισμένα και είναι τα εξής: int main(int argc, char *argv[]) {... Tα ορίσματα περνιούνται στο πρόγραμμα από τη Tα ορίσματα περνιούνται στο πρόγραμμα από τη γραμμή διαταγών τη στιγμή που αρχίζει η εκτέλεσή του.
Σημασία των ορισμάτων Το πρώτο όρισμα argc, το οποίο είναι τύπου ακέραιος, είναι ο αριθμός των ορισμάτων της γραμμής διαταγών, με τα οποία έχει κληθεί το πρόγραμμα. Το δεύτερο όρισμα argv είναι δείκτης για έναν πίνακα συμβολοσειρών ο οποίος περιέχει τα ορίσματα. Κατά σύμβαση argv[] είναι το όνομα με το οποίο κλήθηκε το πρόγραμμα. argv[1],, argv[argc - 1], είναι τα υπόλοιπα ορίσματα με την σειρά που δόθηκαν στη γραμμή εντολής. argv[argc] περιέχει το μηδενικό δείκτη.
Σημασία των ορισμάτων (συν.) Παράδειγμα: Έστω ένα πρόγραμμα C το οποίο έχει τη μορφή: int main(int argc, char *argv[]) { int i = ; for (i=; i<argc; i++) { printf("argv[%d] = \ %s\ \n", i, argv[i]); return ; Θεωρείστε επίσης ότι το εκτελέσιμο αρχείο του παραπάνω προγράμματος έχει ονομαστεί prog. Τότε κατά την κλήση του prog υπό τη μορφή: $./prog.out o opt1 opt2 opt3 έχουμε την εξής ανάθεση τιμών στα ορίσματα της main: argc = 4 argv[] =./prog.out argv[1] = opt1 argv[2] = opt2 argv[3] = opt3
Παράδειγμα 1 Ζητούμενο: πρόγραμμα που κατά την κλήση του με n ορίσματα αντηχεί (echoes) τα n-1 τελευταία στην οθόνη. Για παράδειγμα αν το πρόγραμμα αυτό λέγεται echo, τότε μία κλήση της μορφής: $ echo Hello world! θα εμφάνιζε στην έξοδο $ Hello world! Οι τυπικές παράμετροι ρ της συνάρτησης ρη ηςmain θα έχουν τιμές: argc = 3 argv[] = echo argv[1] = Hello argv[2] = world!
Τέλος Κεφαλαίου 12