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.d0
real(8),pointer :: ptr
real(8),pointer :: ptr2
! - 1. 简单的单一变量指针(有以下几种使用情况)
! a 简单指针赋值
print *,"a:简单指针,ptr获取了realNum1的地址,此时打印ptr和realNum1是相同值"
ptr => realNum1
print *,"ptr=",ptr,"realNum1=",realNum1
! b 在a的基础上修改
print *,""
print *,"b:修改realNum1的值,ptr也发生改变,因为ptr => realNum1,使ptr和realNum1指向同一处内存空间"
realNum1 = 55.d0
print *,"ptr=",ptr,"realNum1=",realNum1
! c 在b基础上
print *,""
print *,"c:修改ptr的值,realNum1也发生变量,原因是ptr和realNum1地址一样"
ptr = 60.d0
print *,"ptr=",ptr,"realNum1=",realNum1
! d 在c的基础上
print *,""
print *,"d:修改ptr指向realNum2,发现此时ptr的值和realNum2相同,而realNum1保持c的结果"
ptr => realNum2
print *,"ptr=",ptr,"realNum2=",realNum2,"realNum1=",realNum1
! e:如果d之后把指针ptr置空 [若要运行将e和f屏蔽]
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分配指针内存了"
allocate(ptr2)
ptr2 = 200.d0 ! 给指针ptr2赋值
print *,"ptr2=",ptr2
! h:在g的基础上
print *,""
print *,"h:ptr2是指针,被allocate分配过,那是否还有指向的属性? 指向还是存在的,但这时侯会存在一个问题, ptr2和realNum1都开辟过空间,而ptr2又指向了realNum1的空间,那就有泄露产生了,因为分配的指针是不会自己释放内存的;"
ptr2 => realNum1
print *,"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
end 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 => arr1
print *,"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 = 6
print *,"arr1",arr1,"p1",p1
! d:数组指针释放
print *,""
print *,"c:可以使用allocate进行内存分配,分配和指向不冲突"
deallocate(p1)
if( associated(p1) == .true. )then
print *,"p1未成功释放"
else
print *,"p1已释放"
endif
end program
运行结果
1.3 派生类(type)指针
同样,用示例说明用法,主要介绍了派生类指针的基础用法和赋值
。
program test
implicit none
! - 3 派生类指针定义
type :: test_type !> 定义派生类
real(8) :: arr(100000)
real(8) :: arr2(200000)
real(8),pointer :: ptr3
end type
type(test_type),target :: typeValue
type(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 =>realNum1
print *,"指针ptype分配内存,赋初值"
write(*,"(a,f10.6,a,f10.6)"),"派生类指针下数组",ptype%arr(1)," 派生类指针的指针",ptype%ptr3
print *,"对于这样的派生类,使用指针是最高效、最省内存的了"
end program
运行结果
1.4 函数指针
同样,用示例说明用法,主要介绍了调用函数指针计算
、将函数指针作为参数在函数之间传递
。
program test
implicit none
! - 4 函数指针
procedure(f), pointer :: pf
real(8) :: fv,x
! -4. 函数指针的使用
! a: 函数指针的简单使用
print *
print *, "函数指针的简单使用"
pf => f
print *, 'pf(2) = ', pf(2.d0) ! 调用f(2.)
pf => g
print *, 'pf(2) = ', pf(2.d0) ! 调用g(2.)
print *
! b: 函数指针可以作为变量进行传值
pf => f
x = 100.d0
call calfun(pf,x,fv)
write( *,*),"函数指针作为参数的运算结果",fv
contains
real function f(x)
real(8), intent(in) :: x
f = x**2
end function f
real function g(x)
real(8), intent(in) :: x
g = x**3
end function g
subroutine calfun(fun,x,fv)
procedure(f),pointer :: fun
real(8),intent(in) :: x
real(8),intent(out) :: fv
fv = fun(x)
end subroutine
end program
2 可运行code
program test_pointer
implicit none
! - 1 简单指针定义
real(8),target :: realNum1 = 5.d0, realNum2 = 100.d0
real(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 type
type(test_type),target :: typeValue
type(test_type),pointer :: ptype ! 定义派生类指针
! - 4 函数指针
procedure(f), pointer :: pf
real(8) :: fv,x
ptr2 => null() ! 指针指向空
! - 1. 简单的单一变量指针(有以下几种使用情况)
! a 简单指针赋值
print *,"a:简单指针,ptr获取了realNum1的地址,此时打印ptr和realNum1是相同值"
ptr => realNum1
print *,"ptr=",ptr,"realNum1=",realNum1
! b 在a的基础上修改
print *,""
print *,"b:修改realNum1的值,ptr也发生改变,因为ptr => realNum1,使ptr和realNum1指向同一处内存空间"
realNum1 = 55.d0
print *,"ptr=",ptr,"realNum1=",realNum1
! c 在b基础上
print *,""
print *,"c:修改ptr的值,realNum1也发生变量,原因是ptr和realNum1地址一样"
ptr = 60.d0
print *,"ptr=",ptr,"realNum1=",realNum1
! d 在c的基础上
print *,""
print *,"d:修改ptr指向realNum2,发现此时ptr的值和realNum2相同,而realNum1保持c的结果"
ptr => realNum2
print *,"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 => realNum1
print *,"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 => arr1
print *,"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 = 6
print *,"arr1",arr1,"p1",p1
! d:数组指针释放
print *,""
print *,"c:可以使用allocate进行内存分配,分配和指向不冲突"
deallocate(p1)
if( associated(p1) == .true. )then
print *,"p1未成功释放"
else
print *,"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 =>realNum1
print *,"指针ptype分配内存,赋初值"
write(*,"(a,f10.6,a,f10.6)"),"派生类指针下数组",ptype%arr(1)," 派生类指针的指针",ptype%ptr3
print *,"对于这样的派生类,使用指针是最高效、最省内存的了"
! -4. 函数指针的使用
! a: 函数指针的简单使用
print *
print *, "函数指针的简单使用"
pf => f
print *, 'pf(2) = ', pf(2.d0) ! 调用f(2.)
pf => g
print *, 'pf(2) = ', pf(2.d0) ! 调用g(2.)
print *
! b: 函数指针可以作为变量进行传值
pf => f
x = 100.d0
call calfun(pf,x,fv)
write( *,*),"函数指针作为参数的运算结果",fv
contains
real function f(x)
real(8), intent(in) :: x
f = x**2
end function f
real function g(x)
real(8), intent(in) :: x
g = x**3
end function g
subroutine calfun(fun,x,fv)
procedure(f),pointer :: fun
real(8),intent(in) :: x
real(8),intent(out) :: fv
fv = fun(x)
end subroutine
end program
程序中若有不理解的地方可以留言讨论,希望对需要的人有些许帮助。
🕝
🕝🕝
🕝🕝🕝
🕝🕝🕝🕝
🕝🕝🕝🕝🕝
🕝🕝🕝🕝🕝🕝
🕝🕝🕝🕝🕝🕝🕝