07-Fortran基础--Fortran指针(Pointer)的使用

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 

  程序中若有不理解的地方可以留言讨论,希望对需要的人有些许帮助。

🕝
🕝🕝
🕝🕝🕝
🕝🕝🕝🕝
🕝🕝🕝🕝🕝
🕝🕝🕝🕝🕝🕝
🕝🕝🕝🕝🕝🕝🕝

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/629871.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

43k Star!推荐一款功能强大的开源笔记软件!

程序员的公众号:源1024,获取更多资料,无加密无套路! 最近整理了一份大厂面试资料《史上最全大厂面试题》,Springboot、微服务、算法、数据结构、Zookeeper、Mybatis、Dubbo、linux、Kafka、Elasticsearch、数据库等等 …

【2024系统架构设计】回顾历史,查缺补漏篇 ③

前言 hello,大家好: 💡💡💡 我们一起来备考软考高级系统架构设计师吧,本专栏提供综合知识、案例科目、论文(论点和部分示例范文)等内容,包括知识点总结和记忆小妙招哦。 🚀🚀🚀 可以减少资料查找和收集的时间,提高效率,我们一起集中精力学习干货吧! 💡…

Lora训练Windows[笔记]

一. 使用kohya_ss的GUI版本(https://github.com/bmaltais/kohya_ss.git) 这个版本跟stable-diffusion-webui的界面很像,只不过是训练模型专用而已,打开的端口同样是7860。 1.双击setup.bat,选择1安装好xformers,pytorch等和cuda…

Linux进程概念总结

这里总结下Linux进程概念总结❗ 冯诺依曼: CPU 运算器与控制器RAM 内存(存储器)Cache 缓存(一种技术)不属于冯诺依曼体系结构。ROM 磁盘(输入输出设备)磁盘 既可以从硬盘读取数据也可以向硬盘…

【全开源】JAVA语聊大厅语音聊天APP系统源码

语聊大厅语音聊天源码:打造专属的语音社交平台 核心功能 多人语音聊天:支持多人同时在线语音聊天,用户可以创建或加入不同的聊天室,与好友或陌生人进行实时互动。语音转文字:提供语音转文字功能,方便用户…

你好 GPT-4o!

你好 GPT-4o! OpenAI公司宣布推出 GPT-4o,这是OpenAI的新旗舰模型,可以实时对音频、视觉和文本进行推理。 GPT-4o(“o”代表“o​​mni”)是迈向更自然的人机交互的一步——它接受文本、音频、图像和视频的任意组合作…

C++二叉搜索树搜索二叉树二叉排序树

C二叉搜索树 1. 二叉搜索树的概念 二叉搜索树(BST,Binary Search Tree),也称为二叉排序树或二叉查找树。它与一般二叉树的区别在于:每个结点必须满足“左孩子大于自己,右孩子小于自己”的规则。在这种规则的约束下,二…

海上定位测量难?千寻星基稳如“定”海神针_0416(update-2)

海上定位测量难?千寻星基稳如“定”海神针 近年来,随着海洋资源的开发和利用,海上定位测量的需求日益增加,它通过测量物体的位置和方向来确定海洋中的各项活动。其准确性和可靠性对于确保海上作业的安全和效率至关重要。 由于海…

想做好抖店?新手、老玩家切勿掉进这些坑,操作要慎重!

大家好,我是电商花花。 很多人都说做抖音小店不需要脑子,会抄就行,难道做店真的就是这样吗? 真的就是会抄,会简单选品,找一些达人就能出单,就能实现睡后收入了吗? 其实并不见得&a…

Latex问题1

问题 添加bib文件的引用后 \bibliographystyle{IEEEtran} \bibliography{IEEEabrv}之后,出现莫名其妙的错误,如下 IEEEabrv.bib是我的参考文献的bib文件,CCS_1.tex是我的tex文件,bib文件中的内容为 ARTICLE{1,author{Capponi,…

精选合作伙伴:如何挑选最适合您小程序商城开发的软件公司

在选择一家合适的软件公司来协助您开发并运营小程序商城时,选择过程无疑是一项关键而复杂的任务。市场上的软件公司繁多,各具特色,那么,如何在这众多的选择中找到最适合您的合作伙伴呢?以下将从需求梳理、公司实力评估…

jiebaNET中文分词器

最近我接手了一个有趣的需求,需要对用户评价进行分词,进行词频统计和情绪分析,并且根据词频权重制成词云图以供后台数据统计,于是我便引入了jieba分词器,但是我发现网上关于jiebaNET相关文档实在太少了,甚至连配置文件…

2.1.2 C++程序设计——程序基本概念

文章目录 展示大纲1、程序基本概念2、基本数据类型3、程序基本语句4、基本运算5、数学库常用函数6、结构化程序设计展示大纲 1、程序基本概念

分享开放原子AtomGit开源协作平台评测报告

AtomGit平台的总体介绍 开放原子开源基金会是致力于推动全球开源事业发展的非营利机构,于 2020 年 6 月在北京成立,由阿里巴巴、百度、华为、浪潮、360、腾讯、招商银行等多家龙头科技企业联合发起。目前有三个主要机构设置,技术监督委员会&…

3-3 基于RYU的流量风暴事件原理与响应策略

在传统网络中,存在着一定的广播流量,占据了一部分的网络带宽。同时,在有环的拓扑中,如果不运行某些协议,广播数据还会引起网络风暴,使网络瘫痪。 如有以下的一个网络拓扑结构(3_2_topoplus.py) …

武汉星起航:亚马逊构建综合性商业生态,卖家买家共享全球化红利

在当今全球化日益加速的时代,亚马逊不仅以其卓越的电商平台服务全球消费者,更通过一系列前沿服务打造了一个综合性的商业生态系统。在这个生态系统中,卖家能够轻松拓展全球业务,买家则享受到了前所未有的购物体验。亚马逊以其独特…

CCF-Csp算法能力认证, 202309-1坐标变换(其一)(C++)含解析

前言 推荐书目,在这里推荐那一本《算法笔记》(胡明),需要PDF的话,链接如下 「链接:https://pan.xunlei.com/s/VNvz4BUFYqnx8kJ4BI4v1ywPA1?pwd6vdq# 提取码:6vdq”复制这段内容后打开手机迅雷…

js之选项卡制作实例

大家好&#xff0c;今天给大家书写选项卡实例&#xff0c;话不多说&#xff0c;直接上干货 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, in…

Vue.js的发展史(一)

Vue.js的发展史&#xff08;一&#xff09; 什么是Vue? Vue (发音为 /vjuː/&#xff0c;类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助你高效地开发…

electron进程间通信

Electron 应用程序的结构非常相似。 作为应用开发者&#xff0c;你将控制两种类型的进程&#xff1a;主进程 和 渲染器进程。 这类似于上文所述的 Chrome 的浏览器和渲染器进程。 主进程 每个 Electron 应用都有一个单一的主进程&#xff0c;作为应用程序的入口点。 主进程在 N…