Puntatori
Principi fondamentali
I puntatori sono variabili con attributo POINTER;i puntatori non sono dei dati ma attributi di dati e devono essere
dichiarati nel modo seguente:
REAL, POINTER :: var
Sono concettualmente descrittori che elencano gli attributi degli oggetti (target) che il puntatore
può indicare ed inoltre esso può indicare anche l'indirizzo, all'occorrenza, d'un TARGET. Non hanno memoria
collegata fino a quando non gli viene assegnata:
ALLOCATE (var)
Nella espressione seguente:
var = var + 2.3
il valore del target di var è usato e modificato. I puntatori non possono essere trasferiti via ingreso/uscita l' istruzione:
WRITE *, var
scrive il valore dell' TARGET di var e non il descrittore in se del puntatore.
Un puntatore può indicare ad altri puntatori e quindi ai loro TARGETS , o ad un oggetto statico che ha
l'attributo del TARGET:
REAL, POINTER :: object
REAL, TARGET :: target_obj
var => object ! pointer assignment
var => target_obj
ma sono digitati nel modo seguente:
INTEGER, POINTER :: int_var
var => int_var ! illegal - types must match
ed,allo stesso modo per gli array i Rank come pure il tipo deve essere conforme.
Un puntatore può essere un componente d'un tipo di dati derivato :
TYPE entry ! type for sparse matrix
REAL value
INTEGER index
TYPE(entry), POINTER :: next ! note recursion
END TYPE entry
e possiamo definire l' inizio d'un link chain collegato:
TYPE(entry), POINTER :: chain
Dopo le ripartizioni e le definizioni adatte, le prime due voci sono state indirizzate come:
chain%value chain%next%value
chain%index chain%next%index
chain%next chain%next%next
ma definiremo normalmente puntatori supplementari indicando, per esempio, prime e le entrate correnti nella lista.
Associazione
La condizione di associazione del puntatore è fornita dal seguente statement:
1)non definito (condizione iniziale);
2)collegato (dopo la ripartizione o un' assegnazione dell'puntatore);
3)deallocato
DEALLOCATE (p, q) ! for returning storage
NULLIFY (p, q) ! for setting to 'null'
La funzione intrinseca ASSOCIATED può verificare la condizione di associazione d'un puntatore definito:
IF (ASSOCIATED(pointer)) THEN
o fra un puntatore definito e un TARGET definito (che può, in se, essere un puntatore):
IF (ASSOCIATED(pointer, target)) THEN
Puntatori nelle espressioni e nelle assegnazioni
Per i tipi intrinsechi noi possiamo passare i puntatori attraverso insiemi differenti dei dati
del TARGET usando lo stesso codice senza alcun movimento di dati. Data la matrice
y = B C z, possiamo scrivere il seguente codice (anche se, in questo caso, lo stesso
risultato potrebbe essere raggiunto più semplicemente attraverso altri mezzi):
REAL, TARGET :: b(10,10), c(10,10), r(10), s(10, z(10)
REAL, POINTER :: a(:,:), x(:), y(:)
INTEGER mult
:
DO mult = 1, 2
IF (mult == 1) THEN
y => r ! no data movement
a => c
x => z
ELSE
y => s ! no data movement
a => b
x => r
END IF
y = MATMUL(a, x) ! common calculation
END DO
Per gli oggetti del tipo di dati derivato dobbiamo distinguere fra il puntatore e la
normale assegnazione .
In:
TYPE(entry), POINTER :: first, current
:
first => current
questo può portare a:
first = current
come a:
first%value = current%value
first%index = current%index
first%next => current%next
Argomenti del puntatore
Se un argomento reale è un puntatore, allora l'argomento fittizio è egualmente un puntatore,
1)deve avere lo stesso rango ,
2)riceve la relativa condizione di associazione dall' argomento reale,
3)restituisce la relativa condizione finale di associazione all' argomento reale (nota: il TARGET può essere non definito!),
4)non può avere l' attributo INTENT (sarebbe ambiguo),
5)richiede un interface block.
Se l' argomento fittizio non è un puntatore, è collegato con il TARGET dell' argomento reale:
REAL, POINTER :: a(:,:)
:
ALLOCATE (a(80, 80))
:
CALL sub(a)
:
SUBROUTINE sub(c)
REAL c(:, :)
Funzioni del puntatore
I risultati di una funzione possono anche avere un attributo puntatore ; ciò è utile se il formato del
risultato dipende dalle calcolazioni effettuate nella funzione, come nel seguente caso:
USE data_handler
REAL x(100)
REAL, POINTER :: y(:)
:
y => compact(x)
dove il modulo handler contiene:
FUNCTION compact(x)
REAL, POINTER :: compact(:)
REAL x(:)
! A procedure to remove duplicates from the array x
INTEGER n
: ! Find the number of distinct values, n
ALLOCATE(compact(n))
: ! Copy the distinct values into compact
END FUNCTION compact
Il risultato può essere usato in un' espressione (ma deve essere associato con un TARGET definito).
Array di puntatori
Questi non esistono come tali: infatti dati
TYPE(entry) :: rows(n)
allora
rows%next ! illegal
potrebbe essere un oggetto, ma con un modello irregolare di memoria. Per questo motivo non sono permessi.
Tuttavia, possiamo realizzare lo stesso effetto definendo un tipo derivato di dati con un puntatore come
relativo componente:
TYPE row
REAL, POINTER :: r(:)
END TYPE
ed allora definendo gli array di questi dati digitare:
TYPE(row) :: s(n), t(n)
dove la memoria per il file può essere assegnata nei pressi, per esempio,
DO i = 1, n
ALLOCATE (t(i)%r(1:i)) ! Allocate row i of length i
END DO
L' assegnazione di array
s = t
è allora equivalente all'assegnazioni del puntatore
s(i)%r => t(i)%r
per tutti i componenti.
Puntatori come pseudonimi dinamici
Dato un array
REAL, TARGET :: table(100,100)
si indicano frequentemente con i sottoscritti statement
table(m:n, p:q)
questi statement possono essere sostituiti con:
REAL, DIMENSION(:, :), POINTER :: window
:
window => table(m:n, p:q)
Gli estremi della finestra sono 1:n-m+1, 1:q-p+1. Similmente, per
tar%u
possiamo usare per esempio
taru = > tar%u
per indicare tutti i componenti di u del tar come
taru(1, 2)
Infine per riepilogare possiamo dire che l'inclusione del puntatore nel fortran 90 comporta l'introduzione
del concetto di array dinamico.