next up previous

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.