ΠΑΝΕΠΙΣΤΗΜΙΟ ΘΕΣΣΑΛΙΑΣ ΤΜΗΜΑ ΜΗΧΑΝΟΛΟΓΩΝ ΜΗΧΑΝΙΚΩΝ ΒΙΟΜΗΧΑΝΙΑΣ Διάλεξη 3: Δείκτες Εαρινό εξάμηνο 2009 ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ Η/Υ Ι. Σαρρής, τηλ.
Δείκτες
Βασικά χαρακτηριστικά
Βασικά χαρακτηριστικά (συνέχεια)
Ανάθεση σε δείκτες
Παράδειγμα INTEGER, POINTER::P INTEGER, TARGET ::X=10, Y=0 P=>X!P=X=10, Y=0, P συσχετισμένος με X Χ=11!Χ=11 και P=11 Χ=10!P=10 και X=10 Y=P!Y=X=10 P=>Y!P=Y=10, X=10, P συσχετισμένος με Y P=>20!P=Y=20, X=10 ! P=>10! Λάθος ! P=>y+1! Λάθος P=10! σωστό P=y+1! σωστό NULLIFY(P)! P μη συσχετισμένος. Δεν έχει τιμή! END
Ανάθεση σε δείκτες (συνέχεια)
INTEGER, POINTER::P1, P2!Με στόχο δείκτη INTEGER, TARGET ::X=10, Y=0 P1=>X! P1=X=10, Y=0,P2 αόριστος P2=>Y! P2=Y=0,P2 συσχετισμένος με το Y P2=>P1! P2=X=10, Y=0,P2 συσχετισμένος με το X P1=>Y! P1=Y=0,P1 συσχετισμένος με το Y END Όταν στόχος είναι ένας άλλος δείκτης, τότε η συσχέτιση γίνεται με το στόχο του. Δηλαδή στο παράδειγμα ο ‘P2’ δείχνει το ‘X’ και θα συνεχίσει να το δείχνει ακόμη και όταν ο ‘P1’ θα δείξει το ‘Y’.
Ανάθεση σε δείκτες (συνέχεια)
Παράδειγμα INTEGER, POINTER::P1, P2 INTEGER, TARGET ::X=10, Y=0 LOGICAL::status P1=>X status=ASSOCIATED(P1)!1).TRUE. status=ASSOCIATED(P1,X)!2).TRUE. status=ASSOCIATED(P1,Y)!3).FALSE. status=ASSOCIATED(P2)!4).FALSE. P2=>Y status=ASSOCIATED(P2)!5).TRUE. P2=>P1 status=ASSOCIATED(P2,P1)!6).TRUE. status=ASSOCIATED(P1,P2)!7).TRUE. status=ASSOCIATED(P2,Y)!8).FALSE. P1=>Y status=ASSOCIATED(P2,P1)!10).TRUE. status=ASSOCIATED(P2,X)!11).TRUE. END
Δέσμευση μνήμης INTEGER, POINTER::P, ARRAY_OF_P(:) INTEGER ::N=10 ALLOCATE(P,ARRAY_OF_P(N)). DEALLOCATE(P,ARRAY_OF_P) Στην παραπάνω περίπτωση ο ‘P’ συσχετίζεται με μια περιοχή μνήμης 4 bytes ‘ARRAY_OF_P’ με μια περιοχή μνήμης 4Χ10 bytes. Χρειάζεται προσοχή για να μην υπάρξουν διαρροές μνήμης INTEGER, POINTER::P1(:), P2(:) INTEGER ::N=10 ALLOCATE(P1(N),P2(N)) NULLIFY(P1) P1=>P2 DEALLOCATE(P2) END Ο P1 δεν συσχετίζεται με τη μνήμη, που όμως παραμένει δεσμευμένη Ο P1 συσχετίζεται με τον P2. Στη συνέχεια όμως η μνήμη αποδεσμεύεται και ο P1 μένει αιωρούμενος με απρόβλεπτα αποτελέσματα
Δείκτες πινάκων Οι δείκτες μπορούν να χρησιμοποιηθούν και σαν δυναμικά ψευδώνυμα ολόκληρων πινάκων ή τμημάτων τους. REAL, TARGET::A(6,6) REAL, POINTER::cntr(:), row(:) cntr=> A(3:4,3:4); row=A(3:) REAL, TARGET::A(-3:2) REAL, POINTER::row(:) row=>A! a) row (-3:2) row=A(:) ! b) row (1:6) row=A(0::2) ! c) row (1:2)
Δείκτες πινάκων (συνέχεια) Αν ο δείκτης συσχετίζεται με τμήμα ενός πίνακα, το κάτω όριο του είναι 1 και το άνω όριο ίσο με την έκταση του τμήματος, έστω και αν το τμήμα είναι ίσο με τον πίνακα. Αν ο δείκτης σχετίζεται με ολόκληρο πίνακα, τα όρια και οι ενδεικτές του είναι ίδια με του πίνακα. Δεν μπορούμε να χρησιμοποιήσουμε διανυσματικούς ενδεικτές για να προσδιορίσουμε τμήμα πίνακα που σχετίζεται με δείκτη. Ο μόνος τρόπος είναι οι τριάδες. Οι πίνακες δεικτών είναι εξ ορισμού ALLOCATABLE και δεν χρειάζονται DEALLOCATE.
Δείκτες και παράγωγοι τύποι Οι δείκτες μπορούν να είναι συστατικά παραγώγων τύπων, ή να συσχετιστούν με μεταβλητές παραγώγων τύπων ή με στοιχεία τους, όπως ακριβώς και με τις μεταβλητές βασικού τύπου. PROGRAM pointers IMPLICIT NONE TYPE example REAL, POINTER:: P(:) END TYPE example INTEGER ::I, J, N TYPE(example)::X(3) DO I=1,3 READ*, N ALLOCATE(X(I)%P(N)) !κάθε φορά διαφορετικό n X(I)%P=(/(J,J=1,N)/) PRINT ‘(10F5.2)’, X(I)%P END DO END PROGRAM pointers
Δείκτες και διαδικασίες Οι δείκτες μπορούν να χρησιμοποιηθούν σαν εικονικές μεταβλητές διαδικασιών ή σαν παράμετροι του ορίσματος της κλήσης τους. Το αποτέλεσμα μιας διαδικασίας τύπου FUNCTION μπορεί να είναι δείκτης Περιορισμοί: 1.Η αντίστοιχη παράμετρος κλήσης πρέπει να είναι επίσης δείκτης του ίδιου τύπου, είδους και τάξης. 2.Ένας εικονικός δείκτης δεν μπορεί να έχει την ιδιότητα INTENT και οι διαδικασίες δεν μπορούν να είναι PURE ή ELEMENTAL. 3.Οι διαδικασίες που χρησιμοποιούν εικονικούς δείκτες ή στόχους πρέπει να έχουν ρητή διεπιφάνεια (θα δούμε γιατί όταν θα μιλήσουμε για τα αντικείμενα). 4.Τέλος, αν μια παράμετρος κλήσης της διαδικασίας είναι δείκτης, ενώ ο αντίστοιχος εικονικός όρος της διαδικασίας δεν είναι, τότε ο εικονικός όρος συσχετίζεται με το στόχο του δείκτη (ο δείκτης απαναφέρεται)
Παράδειγμα PROGRAM pointers IMPLICIT NONE REAL, DIMENSION(0:100)::X REAL, DIMENSION(:), POINTER::P INTEGER:: I X=0.; X(::40)=(/(I,I=1,3)/) CALL nonzero(X,P) PRINT*, P; PRINT*, SIZE(P) CONTAINS SUBROUTINE nonzero(a,b) REAL, DIMENSION(:)::a REAL, DIMENSION(:), POINTER::b INTEGER:: i, j, n n = COUNT(a>1.E-7) ALLOCATE(b(n)) DO j = 1, SIZE(a) IF(a(j)<1.E-7) CYCLE i=i+1 b(i)=a(j) END DO END PROGRAM pointers
Λίστες Οι δείκτες μας δίνουν τη δυνατότητα δημιουργίας δυναμικών δομών όπως οι συνδεδεμένες λίστες (ουρές, σωρούς, δενδριτικές δομές, κλπ) Οι δομές αυτές μας δίνουν την δυνατότητα της κατά βούλησης αύξησης και μείωσης του μεγέθους τους κατά την διάρκεια της εκτέλεσης. TYPE list INTEGER ::value TYPE (list), POINTER::next ! Αναδρομική δήλωση END TYPE list
Παράδειγμα PROGRAM linkedlist IMPLICIT NONE TYPE list INTEGER ::value TYPE (list), POINTER::next END TYPE list TYPE(list), POINTER ::first,last INTEGER:: number, status NULLIFY(first,last) READ*, number IF(number/=0) THEN ALLOCATE(first, STAT=status) IF(status/=0) STOP ‘NOT ENOUGH MEMORY’ last=>first last%next=>NULL() last%value= number reading:DO READ(*,*) number; IF(number==0) EXIT ALLOCATE(last%next, STAT=status) IF(status/=0) STOP ‘NOT ENOUGH MEMORY’ last=>last%next last%next=>NULL() last%value= number END DO reading END IF printing:DO WHILE(ASSOCIATED(first)) PRINT*, first%value first=>first%next END DO printing END PROGRAM linkedlist
Λίστες (συνέχεια) Η περιγραφή του τύπου list είναι αναδρομική Δεν έχουμε δηλώσει πουθενά το μέγεθος της λίστας Η δημιουργία της λίστας μπορεί να χωριστεί σε τέσσερα στάδια 1.Δημιουργείται ο τύπος της λίστας με την αναδρομική δήλωση TYPE list … END TYPE list, και δηλώνονται δύο δείκτες αυτού του τύπου. Αρχικά αποσυσχετίζονται από κάθε πιθανό στόχο. first NULL last NULL
Λίστες (συνέχεια) 2. Για να δημιουργήσουμε το πρώτο στοιχείο της λίστας συσχετίζουμε τους δύο δείκτες μεταξύ τους (last=>first), αποσυσχετίζουμε το επόμενο στοιχείο της λίστας (last%next=>null()) και δίνουμε τιμή (last%value=number) value nextNULL firstlast
Λίστες (συνέχεια) 3. Δημιουργείται κάθε στοιχείο της λίστας (last =>last%next) το επόμενο στοιχείο αποσυσχετίζεται (last%next =>null()) και το τρέχον παίρνει τιμή (last%value=number) value next value nextNULL first last
Λίστες (συνέχεια) value next value next value nextNULL first last 4. Με την εντολή first =>first%next διατρέχουμε την λίστα από την αρχή προς το τέλος της