07-Fortran基礎--Fortran指針Pointer的使用
- 0 引言
- 1 指針(Poionter)的有關內容
- 1.1 一般類型指針
- 1.2 數組指針
- 1.3 派生類(type)指針
- 1.4 函數指針
- 2 可運行code

0 引言
??Fortran是一種廣泛使用的編程語言,特別適合科學計算和數值分析。Fortran 90引入了指針的概念,允許程序員動態地管理內存,并在程序中創建靈活的數據結構,前面已經簡單介紹過指針類型的定義和賦值,這一部分詳細講下指針的幾種用法。
1 指針(Poionter)的有關內容
??在Fortran中,指針是一種特殊的變量類型,用于存儲內存地址。指針可以指向任何類型的數據,包括標量、數組、派生類、函數和其他變量。以下是一些Fortran中使用指針的基本概念和用法:
1.1 一般類型指針
??下面運行示例中包含了簡單類型指針使用
的差不多😀所有情況,可以仔細閱讀注釋進行理解。
implicit none! - 1 簡單指針定義real(8),target :: realNum1 = 5.d0, realNum2 = 100.d0real(8),pointer :: ptr real(8),pointer :: ptr2 ! - 1. 簡單的單一變量指針(有以下幾種使用情況)! a 簡單指針賦值print *,"a:簡單指針,ptr獲取了realNum1的地址,此時打印ptr和realNum1是相同值"ptr => realNum1print *,"ptr=",ptr,"realNum1=",realNum1! b 在a的基礎上修改print *,""print *,"b:修改realNum1的值,ptr也發生改變,因為ptr => realNum1,使ptr和realNum1指向同一處內存空間"realNum1 = 55.d0print *,"ptr=",ptr,"realNum1=",realNum1! c 在b基礎上print *,""print *,"c:修改ptr的值,realNum1也發生變量,原因是ptr和realNum1地址一樣"ptr = 60.d0print *,"ptr=",ptr,"realNum1=",realNum1! d 在c的基礎上print *,""print *,"d:修改ptr指向realNum2,發現此時ptr的值和realNum2相同,而realNum1保持c的結果"ptr => realNum2print *,"ptr=",ptr,"realNum2=",realNum2,"realNum1=",realNum1! e:如果d之后把指針ptr置空 [若要運行將e和f屏蔽]nullify(ptr)print *,""print *,"e:使ptr指向為空,發現打印ptr會報錯; 僅僅ptr的指向噶了,并不影響它指向的空間"if(associated(ptr) == .true.)thenprint *,"ptr=",ptr,"realNum2=",realNum2,"realNum1=",realNum1elseprint *,"ptr=,Null ","realNum2=",realNum2,"realNum1=",realNum1endif!! f:如果d之后把指針ptr釋放了(deallocate)!print *,""!print *,"f:執行這一步之前將e先屏蔽,使用deallocate釋放調指針ptr,從輸出結果可以看出,僅僅ptr的指向噶了,并不影響它指向的空間"!deallocate(ptr)!if(associated(ptr) == .true.)then! print *,"ptr=",ptr,"realNum2=",realNum2,"realNum1=",realNum1!else! print *,"ptr=,Null ","realNum2=",realNum2,"realNum1=",realNum1!endif! g:給指針分配內存print *,""print *,"g:既然可以使用deallocate釋放指針,那當然也可以用allocate分配指針內存了"allocate(ptr2)ptr2 = 200.d0 ! 給指針ptr2賦值print *,"ptr2=",ptr2! h:在g的基礎上print *,""print *,"h:ptr2是指針,被allocate分配過,那是否還有指向的屬性? 指向還是存在的,但這時侯會存在一個問題, ptr2和realNum1都開辟過空間,而ptr2又指向了realNum1的空間,那就有泄露產生了,因為分配的指針是不會自己釋放內存的;"ptr2 => realNum1print *,"ptr2=",ptr2,"realNum1=",realNum1! i: 在h的基礎上print *,""print *,"i:指針ptr和指針ptr2之間的關系是怎樣的?讓ptr=>ptr2打印結果,發現ptr和ptr2此時指向的為同一空間,值都為realNum1;"ptr=>ptr2 print *,"ptr=",ptr,"ptr2=",ptr2,"realNum1=",realNum1end program
運行結果

1.2 數組指針
??同樣,用示例說明用法,主要介紹了數組指針基礎用法
、用指針進行數組截斷
、分析對內存的影響
。
implicit none! - 2 指針數組定義integer,allocatable :: ind(:)real(8),target :: arr1(3),arr2(5)real(8),pointer :: p1(:) !> 指針數組 real(8),pointer :: p2(:) !> 指針數組 ! 先給arr1和arr2賦值call RANDOM_SEED()call RANDOM_NUMBER(arr1)arr2 = 5.d0! a:數組指針簡單使用print *,""print *,"a:指針ptr數組簡單使用,二者地址一致打印結果相同,同簡單類型指針類似,p1和arr1任何一個被該,另一個也隨著被改;"p1 => arr1print *,"arr1",arr1,"p1",p1! b:數組指針的特別用法print *,""print *,"b:數組指針可以指向數組中特定索引的元素(a:b),實現拆分數組,指針可以多次指向同一目標, 指向的空間/內存必須是連續的;"p1 => arr1(2:3)print *,"arr1",arr1,"p1",p1! c:分配內存print *,""print *,"c:可以使用allocate進行內存分配,分配和指向不沖突"allocate(p1(6))p1 = 6print *,"arr1",arr1,"p1",p1! d:數組指針釋放print *,""print *,"c:可以使用allocate進行內存分配,分配和指向不沖突"deallocate(p1)if( associated(p1) == .true. )thenprint *,"p1未成功釋放"elseprint *,"p1已釋放"endifend program
運行結果

1.3 派生類(type)指針
??同樣,用示例說明用法,主要介紹了派生類指針的基礎用法和賦值
。
program testimplicit none! - 3 派生類指針定義type :: test_type !> 定義派生類real(8) :: arr(100000)real(8) :: arr2(200000)real(8),pointer :: ptr3 end typetype(test_type),target :: typeValuetype(test_type),pointer :: ptype ! 定義派生類指針! -3. 派生類中指針使用較為常見,因為派生類中可能會同時存在多個大數組,對內存是致命傷害! - a:派生指針的賦值ptype => typeValue ! 先給指針指向目標,此時二者表示同一內存區域call RANDOM_NUMBER(ptype%arr) ! 給派生數組賦值ptype%ptr3 =>realNum1 ! 給指針的指針賦值print *print *,"派生類指針初始化"write(*,"(a,f10.6,a,f10.6)"),"派生類指針下數組",ptype%arr(1)," 派生類指針的指針",ptype%ptr3! - b:指針ptype內存釋放?print *deallocate(ptype)print *,"釋放指針ptype,不影響派生變量typeValue前面的賦值"write(*,"(a,f10.6,a,f10.6)"),"派生類指針下數組",typeValue%arr(1)," 派生類指針的指針",typeValue%ptr3! -c:派生類指針內存分配 print *allocate(ptype)call RANDOM_NUMBER(ptype%arr) ! 指針賦值ptype%ptr3 =>realNum1print *,"指針ptype分配內存,賦初值"write(*,"(a,f10.6,a,f10.6)"),"派生類指針下數組",ptype%arr(1)," 派生類指針的指針",ptype%ptr3print *,"對于這樣的派生類,使用指針是最高效、最省內存的了"end program
運行結果

1.4 函數指針
??同樣,用示例說明用法,主要介紹了調用函數指針計算
、將函數指針作為參數在函數之間傳遞
。
program testimplicit none! - 4 函數指針 procedure(f), pointer :: pfreal(8) :: fv,x! -4. 函數指針的使用! a: 函數指針的簡單使用print *print *, "函數指針的簡單使用"pf => fprint *, 'pf(2) = ', pf(2.d0) ! 調用f(2.)pf => gprint *, 'pf(2) = ', pf(2.d0) ! 調用g(2.)print *! b: 函數指針可以作為變量進行傳值pf => fx = 100.d0call calfun(pf,x,fv)write( *,*),"函數指針作為參數的運算結果",fvcontainsreal function f(x)real(8), intent(in) :: xf = x**2end function freal function g(x)real(8), intent(in) :: xg = x**3end function gsubroutine calfun(fun,x,fv)procedure(f),pointer :: funreal(8),intent(in) :: xreal(8),intent(out) :: fvfv = fun(x)end subroutineend program

2 可運行code
program test_pointerimplicit none! - 1 簡單指針定義real(8),target :: realNum1 = 5.d0, realNum2 = 100.d0real(8),pointer :: ptr real(8),pointer :: ptr2 ! - 2 指針數組定義integer,allocatable :: ind(:)real(8),target :: arr1(3),arr2(5)real(8),pointer :: p1(:) !> 指針數組 real(8),pointer :: p2(:) !> 指針數組 ! - 3 派生類指針定義type :: test_type !> 定義派生類real(8) :: arr(100000)real(8) :: arr2(200000)real(8),pointer :: ptr3 end typetype(test_type),target :: typeValuetype(test_type),pointer :: ptype ! 定義派生類指針! - 4 函數指針 procedure(f), pointer :: pfreal(8) :: fv,xptr2 => null() ! 指針指向空! - 1. 簡單的單一變量指針(有以下幾種使用情況)! a 簡單指針賦值print *,"a:簡單指針,ptr獲取了realNum1的地址,此時打印ptr和realNum1是相同值"ptr => realNum1print *,"ptr=",ptr,"realNum1=",realNum1! b 在a的基礎上修改print *,""print *,"b:修改realNum1的值,ptr也發生改變,因為ptr => realNum1,使ptr和realNum1指向同一處內存空間"realNum1 = 55.d0print *,"ptr=",ptr,"realNum1=",realNum1! c 在b基礎上print *,""print *,"c:修改ptr的值,realNum1也發生變量,原因是ptr和realNum1地址一樣"ptr = 60.d0print *,"ptr=",ptr,"realNum1=",realNum1! d 在c的基礎上print *,""print *,"d:修改ptr指向realNum2,發現此時ptr的值和realNum2相同,而realNum1保持c的結果"ptr => realNum2print *,"ptr=",ptr,"realNum2=",realNum2,"realNum1=",realNum1!! e:如果d之后把指針ptr置空!nullify(ptr)!print *,""!print *,"e:使ptr指向為空,發現打印ptr會報錯,僅僅ptr的指向噶了,并不影響它指向的空間"!if(associated(ptr) == .true.)then! print *,"ptr=",ptr,"realNum2=",realNum2,"realNum1=",realNum1!else! print *,"ptr=,Null ","realNum2=",realNum2,"realNum1=",realNum1!endif!!! f:如果d之后把指針ptr釋放了(deallocate)!print *,""!print *,"f:執行這一步之前將e先屏蔽,使用deallocate釋放調指針ptr,從輸出結果可以看出,僅僅ptr的指向噶了,并不影響它指向的空間"!deallocate(ptr)!if(associated(ptr) == .true.)then! print *,"ptr=",ptr,"realNum2=",realNum2,"realNum1=",realNum1!else! print *,"ptr=,Null ","realNum2=",realNum2,"realNum1=",realNum1!endif! g:給指針分配內存print *,""print *,"g:既然可以使用deallocate釋放指針,那當然也可以分配指針"allocate(ptr2)ptr2 = 200.d0 ! 給指針ptr2賦值print *,"ptr2=",ptr2! h:在g的基礎上print *,""print *,"h:ptr2是指針,被allocate分配過,那是否還有指向的屬性? 指向還是存在的,但這時侯會存在一個問題,&ptr2和realNum1都開辟過空間,而ptr2又指向了realNum1的空間,那就有泄露產生了,因為分配的指針是不會自己釋放內存的;"ptr2 => realNum1print *,"ptr2=",ptr2,"realNum1=",realNum1! i: 在h的基礎上print *,""print *,"i:指針ptr和指針ptr2之間的關系是怎樣的?讓ptr=>ptr2打印結果,發現ptr和ptr2此時指向的為同一空間,值都為realNum1;"ptr=>ptr2 print *,"ptr=",ptr,"ptr2=",ptr2,"realNum1=",realNum1! -2. 指針數組的使用! 先給arr1和arr2賦值call RANDOM_SEED()call RANDOM_NUMBER(arr1)arr2 = 5.d0! a:數組指針簡單使用print *,""print *,"a:指針ptr數組簡單使用,二者地址一致打印結果相同,同簡單類型指針類似,p1和arr1任何一個被該,另一個也隨著被改;"p1 => arr1print *,"arr1",arr1,"p1",p1! b:數組指針的特別用法print *,""print *,"b:數組指針可以指向數組中特定索引的元素(a:b),實現拆分數組,指針可以多次指向同一目標, 指向的空間/內存必須是連續的;"p1 => arr1(2:3)print *,"arr1",arr1,"p1",p1! c:分配內存print *,""print *,"c:可以使用allocate進行內存分配,分配和指向不沖突"allocate(p1(6))p1 = 6print *,"arr1",arr1,"p1",p1! d:數組指針釋放print *,""print *,"c:可以使用allocate進行內存分配,分配和指向不沖突"deallocate(p1)if( associated(p1) == .true. )thenprint *,"p1未成功釋放"elseprint *,"p1已釋放"endif! -3. 派生類中指針使用較為常見,因為派生類中可能會同時存在多個大數組,對內存是致命傷害! - a:派生指針的賦值ptype => typeValue ! 先給指針指向目標,此時二者表示同一內存區域call RANDOM_NUMBER(ptype%arr) ! 給派生數組賦值ptype%ptr3 =>realNum1 ! 給指針的指針賦值print *print *,"派生類指針初始化"write(*,"(a,f10.6,a,f10.6)"),"派生類指針下數組",ptype%arr(1)," 派生類指針的指針",ptype%ptr3! - b:指針ptype內存釋放?print *deallocate(ptype)print *,"釋放指針ptype,不影響派生變量typeValue前面的賦值"write(*,"(a,f10.6,a,f10.6)"),"派生類指針下數組",typeValue%arr(1)," 派生類指針的指針",typeValue%ptr3! -c:派生類指針內存分配 print *allocate(ptype)call RANDOM_NUMBER(ptype%arr) ! 指針賦值ptype%ptr3 =>realNum1print *,"指針ptype分配內存,賦初值"write(*,"(a,f10.6,a,f10.6)"),"派生類指針下數組",ptype%arr(1)," 派生類指針的指針",ptype%ptr3print *,"對于這樣的派生類,使用指針是最高效、最省內存的了"! -4. 函數指針的使用! a: 函數指針的簡單使用print *print *, "函數指針的簡單使用"pf => fprint *, 'pf(2) = ', pf(2.d0) ! 調用f(2.)pf => gprint *, 'pf(2) = ', pf(2.d0) ! 調用g(2.)print *! b: 函數指針可以作為變量進行傳值pf => fx = 100.d0call calfun(pf,x,fv)write( *,*),"函數指針作為參數的運算結果",fvcontainsreal function f(x)real(8), intent(in) :: xf = x**2end function freal function g(x)real(8), intent(in) :: xg = x**3end function gsubroutine calfun(fun,x,fv)procedure(f),pointer :: funreal(8),intent(in) :: xreal(8),intent(out) :: fvfv = fun(x)end subroutineend program
??程序中若有不理解的地方可以留言討論,希望對需要的人有些許幫助。
🕝
🕝🕝
🕝🕝🕝
🕝🕝🕝🕝
🕝🕝🕝🕝🕝
🕝🕝🕝🕝🕝🕝
🕝🕝🕝🕝🕝🕝🕝