ΠΑΝΕΠΙΣΤΗΜΙΟ ΘΕΣΣΑΛΙΑΣΤΜΗΜΑ ΜΗΧΑΝΟΛΟΓΩΝ ΜΗΧΑΝΙΚΩΝ ΒΙΟΜΗΧΑΝΙΑΣ
Διάλεξη 4: Δείκτες, συναρτήσεις και διαδικασίες
Εαρινό εξάμηνο 2009
ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ Η/ΥΙ. Σαρρής, [email protected], τηλ. 2421074090
Παράδειγμα
INTEGER, POINTER ::PINTEGER, TARGET ::X=10, Y=0
P=>XΧ=11Χ=10Y=PP=>YP=>20P=>y+1P=10P=y+1NULLIFY(P)
END
Ανάθεση σε δείκτες (συνέχεια)
Δείκτες πινάκων
Οι δείκτες μπορούν να χρησιμοποιηθούν και σαν δυναμικά ψευδώνυμα ολόκληρων πινάκων ή τμημάτων τους.
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.
Δείκτες και διαδικασίες
• Οι δείκτες μπορούν να χρησιμοποιηθούν σαν εικονικές μεταβλητές διαδικασιών ή σαν παράμετροι του ορίσματος της κλήσης τους.
• Το αποτέλεσμα μιας διαδικασίας τύπου FUNCTION μπορεί να είναι δείκτης
Περιορισμοί:1. Η αντίστοιχη παράμετρος κλήσης πρέπει να είναι επίσης δείκτης του ίδιου
τύπου, είδους και τάξης.2. Ένας εικονικός δείκτης δεν μπορεί να έχει την ιδιότητα INTENT και οι
διαδικασίες δεν μπορούν να είναι PURE ή ELEMENTAL.3. Οι διαδικασίες που χρησιμοποιούν εικονικούς δείκτες ή στόχους πρέπει
να έχουν ρητή διεπιφάνεια (θα δούμε γιατί όταν θα μιλήσουμε για τα αντικείμενα).
4. Τέλος, αν μια παράμετρος κλήσης της διαδικασίας είναι δείκτης, ενώ ο αντίστοιχος εικονικός όρος της διαδικασίας δεν είναι, τότε ο εικονικός όρος συσχετίζεται με το στόχο του δείκτη (ο δείκτης απαναφέρεται)
Παράδειγμα 1
PROGRAM pointersIMPLICIT 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 SUBROUTINE nonzeroEND PROGRAM pointers
Παράδειγμα 2
PROGRAM pointersIMPLICIT NONE
REAL, DIMENSION(0:100) ::X REAL, DIMENSION(:), POINTER ::P INTEGER:: I, n X=0.; X(::40)=(/(I,I=1,3)/) n = COUNT(X>1.E-7) ALLOCATE(P(n)) CALL nonzero(X,P) PRINT*, P; PRINT*, SIZE(P)
CONTAINS SUBROUTINE nonzero(a,b) REAL, DIMENSION(:) ::a,b INTEGER:: i, j DO j = 1, SIZE(a)
IF(a(j)<1.E-7) CYCLE i=i+1 b(i)=a(j) END DO END SUBROUTINE nonzeroEND PROGRAM pointers
Παράδειγμα 3
PROGRAM pointersIMPLICIT NONE
REAL, DIMENSION(0:100) ::X REAL, DIMENSION(:), POINTER ::P INTEGER:: I X=0.; X(::40)=(/(I,I=1,3)/)
P=> nonzero(X) PRINT*, P; PRINT*, SIZE(P)
CONTAINS FUNCTION nonzero(a) REAL, DIMENSION(:) ::a REAL, DIMENSION(:), POINTER :: nonzero INTEGER:: n, i, j n = COUNT(a>1.E-7) ALLOCATE(nonzero(n)) DO j = 1, SIZE(a)
IF(a(j)<1.E-7) CYCLE i=i+1 nonzero(i)=a(j) END DO END FUNCTION nonzeroEND PROGRAM pointers
Παράδειγμα 4
PROGRAM pointersIMPLICIT NONE REAL, DIMENSION(0:100) ::X REAL, DIMENSION(:), POINTER ::P INTEGER:: I
INTERFACE FUNCTION nonzero(a) IMPLICIT NONE REAL, DIMENSION(:) ::a REAL, DIMENSION(:), POINTER :: nonzero END FUNCTION nonzero END INTERFACE X=0.; X(::40)=(/(I,I=1,3)/) P=> nonzero(X) PRINT*, P; PRINT*, SIZE(P)END PROGRAM pointers
FUNCTION nonzero(a) IMPLICIT NONE REAL, DIMENSION(:) ::a REAL, DIMENSION(:), POINTER :: nonzero INTEGER:: n, i, j n = COUNT(a>1.E-7) ALLOCATE(nonzero(n)) DO j = 1, SIZE(a)
IF(a(j)<1.E-7) CYCLE i=i+1 nonzero(i)=a(j) END DO END FUNCTION nonzero
Εξωτερικές διαδικασίες
• Ιστορικά οι εξωτερικές διαδικασίες ήταν το μόνο διαθέσιμο είδος διαδικασιών στην Fortran 77
• Η χρήση τους στην Fortran 90 περιορίζεται στην αυτόματη επίλυση ολοκληρωμένων υπο-προβλημάτων.
• Όπως και οι εσωτερικές διαδικασίες είναι και αυτές τύπου SUBROUTINE ή FUNCTION
• Δεν περιέχονται μέσα στην έκταση CONTAINS…END, αλλά είτε σε ένα άλλο αρχείο πηγαίου κώδικα (με την κατάληξη .F90) ή μετά από την πρόταση END PROGRAM
• Κάθε εξωτερική διαδικασία μεταγλωττίζεται ξεχωριστά, μπορεί να περιέχει εσωτερικές διαδικασίες και μπορούν να έχουν πολλαπλές εισόδους.
Εξωτερικές διαδικασίες (συνέχεια)
• Η κυριότερη διαφορά με τα άλλα είδη διαδικασιών είναι ότι οι εξωτερικές διαδικασίες δεν έχουν ρητή διεπιφάνεια. Πρακτικά αυτό σημαίνει ότι:1. Ο μεταγλωττιστής δεν ξέρει κατά την μεταγλώττιση τον τρόπο
κλίσης της διαδικασίας.2. Ο προγραμματιστής πρέπει να έχει φροντίσει ώστε να καλεί την
εξωτερική διαδικασία με τον σωστό τρόπο 3. Υπάρχει η δυνατότητα να δηλώσουμε ρητά την διεπιφάνεια των
εξωτερικών διαδικασιών χρησιμοποιώντας την δομή INTERFACE… END INTERFACE, πχ
INTERFACE [γενικός ορισμός][διεπιφάνειες][MODULE PROCEDURE λίστα διαδικασιών]
END INTERFACE
Όπου, [διεπιφάνειες] : Η αρχική και η τελική πρόταση μιας ή περισσότερων
διαδικασιών μαζί με το τμήμα δηλώσεων της διαδικασίας.
Παραδείγματα
INTERFACE
REAL FUNCTION f(x,y) REAL, INTENT(IN)::x,y END FUNCTION f
SUBROUTINE fa(x,y,z) REAL, INTENT(IN)::x,y REAL, INTENT(OUT)::z END SUBROUTINE fa
END INTERFACE
PROGRAM Prog_interfaceIMPLICIT NONE INTERFACE INTEGER ELEMENTAL FUNCTION f(x) INTEGER, INTENT(IN)::x END FUNCTION f END INTERFACE
INTEGER::I INTEGER, DIMENTION(5)::a=(/(i,i=1,5)/)
PRINT*, f(a)
END PROGRAM Prog_interface
INTEGER ELEMENTAL FUNCTION f(x) INTEGER, INTENT(IN)::x f=x**2-1 END FUNCTION f
Παρατηρήσεις
• Αν στο προηγούμενο παράδειγμα ξεχάσουμε την δομή INTERFACE, τότε θα δούμε ότι ο μεταγλωττιστής δεν θα μπορεί να επισημάνει το όνομα της διαδικασίας και θα βγάλει το μήνυμα λάθους:
Error: unresolved external
• Εναλλακτικά μπορούμε να κάνουμε γνωστή την ύπαρξη της διαδικασίας χρησιμοποιώντας την εντολή EXTERNAL, π.χ:
INTEGER, EXTERNAL:: f
• Γενικά, προτείνουμε την χρήση της δομής INTERFACE αφού γνωστοποιεί στο πρόγραμμα που την καλεί την ύπαρξη της εξωτερικής διαδικασίας και ταυτόχρονα διασφαλίζει την αντιστοίχηση των όρων των δύο ορισμάτων
Παρατηρήσεις (συνέχεια)
Η χρήση ρητών διεπιφανειών είναι υποχρεωτική μόνο στις εξής περιπτώσεις:
1. Όταν χρησιμοποιούμε εικονικούς όρους που έχουν δηλωθεί ως OPTIONAL.2. Όταν το αποτέλεσμα μιας FUNCTION είναι πίνακας3. Όταν το αποτέλεσμα μιας FUNCTION είναι δείκτης4. Όταν το αποτέλεσμα μιας FUNCTION είναι αλφαριθμητικό με άγνωστο μήκος5. Όταν χρησιμοποιούμε πίνακα υποθετικής μορφής6. Όταν η διαδικασία έχει εικονικούς όρους με τις ιδιότητες POINTER ή TARGET.7. Όταν χρησιμοποιούμε λέξεις κλειδιά στο όρισμα κλήσης μιας διαδικασίας.8. Όταν η διαδικασία είναι γενική (όταν χρησιμοποιούμε το ίδιο όνομα για την
κλήση διαφορετικών διαδικασιών ανάλογα με το είδος των όρων του ορίσματος)
9. Όταν οι διαδικασίες είναι PURE, κλπ
Λίστες
Οι δείκτες μας δίνουν τη δυνατότητα δημιουργίας δυναμικών δομών όπως οι συνδεδεμένες λίστες (ουρές, σωρούς, δενδριτικές δομές, κλπ)
Οι δομές αυτές μας δίνουν την δυνατότητα της κατά βούλησης αύξησης και μείωσης του μεγέθους τους κατά την διάρκεια της εκτέλεσης.
TYPE list INTEGER ::value TYPE (list), POINTER::next ! Αναδρομική δήλωσηEND TYPE list
Λίστες (συνέχεια)
• Η περιγραφή του τύπου list είναι αναδρομική
• Δεν έχουμε δηλώσει πουθενά το μέγεθος της λίστας
• Η δημιουργία της λίστας μπορεί να χωριστεί σε τέσσερα στάδια1. Δημιουργείται ο τύπος της λίστας με την αναδρομική δήλωση TYPE list …
END TYPE list, και δηλώνονται δύο δείκτες αυτού του τύπου. Αρχικά αποσυσχετίζονται από κάθε πιθανό στόχο.
first
NULL
last
NULL
Λίστες (συνέχεια)
2. Για να δημιουργήσουμε το πρώτο στοιχείο της λίστας συσχετίζουμε τους δύο δείκτες μεταξύ τους (last=>first), αποσυσχετίζουμε το επόμενο στοιχείο της λίστας (last%next=>null()) και δίνουμε τιμή (last%value=number)
value
next NULL
first last
Λίστες (συνέχεια)
3. Δημιουργείται κάθε στοιχείο της λίστας (last =>last%next) το επόμενο στοιχείο αποσυσχετίζεται (last%next =>null()) και το τρέχον παίρνει τιμή (last%value=number)
value
next
value
next NULL
first last
Λίστες (συνέχεια)
value
next
value
next
value
next NULL
first last
4. Με την εντολή first =>first%next διατρέχουμε την λίστα από την αρχή προς το τέλος της
Παράδειγμα
PROGRAM linkedlistIMPLICIT 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 readingEND IFprinting:DO WHILE(ASSOCIATED(first))PRINT*, first%valuefirst=>first%nextEND DO printingEND PROGRAM linkedlist
Top Related