12. Pekare

12.0 Inledning

Pekare har införts i Fortran 90, men inte på det vanliga sättet, som i de flesta andra språk med en egen datatyp, utan i stället som ett attribut till de andra datatyperna. Anledningen till det nya sättet är främst att pekare som en egen datatyp ökar risken för felaktig användning. En variabel med pekarattribut kan användas dels som en vanlig variabel, dels på ett antal nya sätt. Pekare i Fortran 90 är således inte minnesadresser som i flera andra programspråk eller i vissa Fortran-varianter, utan är snarare ett extra namn (alias). Den ökade säkerheten erhålls genom att inte bara varje variabel som skall användas som pekare måste ges attributet POINTER, utan att dessutom alla variabler som skall pekas på måste ges attributet TARGET. Detta krav gäller dock inte pekare, som kan peka på varandra utan något TARGET attribut. Ett exempel förklarar hur det fungerar.
        REAL, TARGET    :: B(10,10)
        REAL, POINTER     :: A(:,:)
        A => B
Ovan har matrisen B deklarerats fullständigt, dvs dimensionen har angetts explicit. Dessutom har det angetts att den kan vara mål för en pekare. Matrisen A, som skall användas som pekare, måste deklareras som en matris, dvs ges rätt antal dimensioner (rang), men omfånget för dessa bestäms först vid tilldelningen (egentligen är det inte en tilldelning utan en pekar-associering), vilken sker med =>. Observera att pekar-tilldelningen inte innebär att data i matrisen B kopieras över till matrisen A (vilket skulle tagit relativt stora datorresurser i anspråk), utan det är en adress som genereras. Att "flytta" data med pekare är således mycket effektivt. Alternativt kan en pekare associeras med kommandot ALLOCATE och av-associeras med DEALLOCATE, i vårt fall till exempel
        ALLOCATE (A(5,5))
        DEALLOCATE (A)
Det finns en inbyggd funktion ASSOCIATED för att undersöka om en pekare är associerad (och även om den är associerad med ett visst mål) och ett kommando NULLIFY för att avsluta associeringen.
        IF ( ASSOCIATED (A)   ) WRITE(6,*) ' A associerad'
        IF ( ASSOCIATED (A,B) ) WRITE(6,*) ' A associerad med B'
        NULLIFY (A) 
Notera vidare att en pekare i Fortran 90 har både typ och rang, och att dessa måste överensstämma med motsvarande hos målet. Detta ökar säkerheten vid användning av pekare, man kan därför ej av misstag vid användningen av en viss pekare ändra värden på variabler av andra datatyper. Att man måste deklarera att en variabel kan vara mål ökar dessutom både säkerheten och kompileringseffektiviteten.

12.1 Enkla pekare

Det gäller att tänka sig för när man använder pekare. I det följande enkla exemplet tittar vi på vanliga skalära flyttal.
        REAL, TARGET    :: A
        REAL, POINTER   :: P, Q
        A = 3.1416
        P => A
        Q => P
        A = 2.718
        WRITE(6,*) Q
Här blir värdet av Q lika med 2,718 eftersom både P och Q pekar på samma verkliga variabel A, och den har just ändrat värde från 3,1416 till 2,718. Vi gör nu en enkel variation.
        REAL, TARGET    :: A, B
        REAL, POINTER   :: P, Q
        A = 3.1416  
        B = 2.718
        P => A         
        Q => B
Här är nu värdet av både A och P lika med 3,1416 och värdet av både B och Q är 2,718. Om vi nu ger satsen
        Q = P
så får samtliga fyra variabler värdet 3,1416, det får således samma effekt som
        B = A
Om vi i stället gett satsen
        Q => P
så hade de tre variablerna A, P och Q fått värdet 3,1416, medan B behållet värdet 2,718. I det senare fallet pekar nämligen Q bara på samma variabel som P, medan i det första fallet Q blir samma som P.

12.2 Pekare och fält

En enkel användning av pekare är att ge namn till fältsektioner.
        REAL, TARGET    :: B(10,10)
        REAL, POINTER   :: A(:), C(:)
        A => B(4,:)   ! Vektorn A blir fjärde raden och
        C => B(:,4)   ! vektorn C blir fjärde kolumnen
                      ! av matrisen B
Det är inte nödvändigt att ta ut hela sektioner, utan man kan ta ut bara en del. I följande exempel tar vi ut en delmatris FONSTER av en stor matris MATRIS.
        REAL, TARGET    :: MATRIS(100,100)
        REAL, POINTER     :: FONSTER(:,:)
        INTEGER             :: N1, N2, M1, M2
        FONSTER => MATRIS(N1:M1,N2:M2)
Om man senare vill ändra dimensioneringen av delmatrisen FONSTER så är det bara att göra en ny pekar-tilldelning. Observera dock att indexen i FONSTER inte går från N1 till M1 respektive N2 till M2 utan från 1 till M1-N1+1 respektive 1 till M2-N2+1.

Det finns inte fält av pekare direkt i Fortran 90, men man kan konstruera sådana genom att skapa en ny datatyp. Ett exempel är att lagra en vänstertriangulär matris som rader med varierande längd. Inför först den nya typen RAD

        TYPE RAD
                REAL, POINTER :: R(:)
        END TYPE
och deklarera därefter de två vänstertriangulära matriserna V och L som vektorer av rader med varierande längd.
        INTEGER   :: N
        TYPE(RAD) :: V(N), L(N)
Därefter allokeras matrisen V enligt nedan (och motsvarande för L).
     DO I = 1, N
        ALLOCATE (V(I)%R(1:I))  ! Varierande radlängd
     END DO
Satsen
        V = L 
blir då ekvivalent med att göra
        V(I)%R => L(I)%R 
för alla komponenterna, dvs alla värdena på I.

Observera att i denna tillämpning erfordras inget mål (TARGET) för pekarna!

Man kan även använda pekare för att deklarera en vektor på ett sådant sätt att den tilldelas sin storlek (sitt omfång) i en subrutin men kan användas i huvudprogrammet. Detta ger då en dynamisk minnesallokering. Detta har diskuterats utförligt i sektion 4.3.2.

Notera att vid denna användning av pekare behövs inget deklarerat som TARGET, begreppet POINTER är snarast att betrakta som ett alternativ till ALLOCATABLE.

Viktiga tillämpningar av pekare är listor och träd, liksom dynamiska fält.

Övningar.

(12.1) Använd pekare för att på ett listigt sätt tilldela alla jämna element av en vektor värdet 13 och alla udda element värdet 17.
Lösning.

(12.2) Deklarera två pekare och låt den ena peka på en hel vektor och den andra på det sjunde elementet i samma vektor.
Lösning.

Avancerad användning av subrutiner och funktioner Innehåll Diverse begrepp från Fortran 77


Senast modifierad: 3 maj 1999
boein@nsc.liu.se