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.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 

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java代码混淆工具ProGuard混淆插件

java代码混淆工具ProGuard混淆插件 介绍 ProGuard是一个纯java编写的混淆工具,有客户端跟jar包两种使用方式。可以将程序打包为jar,然后用工具进行混淆,也可以在maven中导入ProGuard的插件,对代码进行混淆。 大家都知道 java代…

【华为OD机试-C卷D卷-200分】田忌赛马(C++/Java/Python)

【华为OD机试】-(A卷+B卷+C卷+D卷)-2024真题合集目录 【华为OD机试】-(C卷+D卷)-2024最新真题目录 题目描述 给定两个只包含数字的数组a,b,调整数组 a 里面的数字的顺序,使得尽可能多的a[i] > b[i]。 数组a和b中的数字各不相同。 输出所有可以达到最优结果的a数组的…

SadTalker 自定义容器化部署配置

Docker 环境检查 执行docker info 查看环境种是否有安装docker,否则首先安装好docker 运行环境。在线环境安装执行执行两条指令即可 sudo apt install docker sudo apt-get install docker-ce sudo apt-get install docker-composesudo systemctl restart dockerG…

langchain源码

itemgetter:返回一个函数,函数取输入dict的某个指定key Runnable 的基本方法有 invoke、 batch、 await、 ainvoke、 abatch 同步转异步 Runnable 还具有的方法:bind、 with_config。 input_schema 属性、output_schema 属性 with_retry方…

Uniapp H5开发常见问题解析

引言 在移动应用开发领域,Uniapp已经成为一个备受瞩目的技术框架,其跨平台能力和高效开发特性使得开发者能够更加便捷地构建出功能丰富、性能优越的应用程序。特别是在H5开发中,Uniapp的应用场景日益广泛,然而,随之而…

Vue2之使用provide和inject实现两个不相干组件之间的通信

Vue2之使用provide和inject实现两个不相干组件之间的通信 文章目录 Vue2之使用provide和inject实现两个不相干组件之间的通信1. 祖先组件中使用provide提供数据2.后代组件A中使用inject注入并使用数据3.后代组件B中使用inject注入并使用数据 在Vue 2中以使用provide和inject来实…

[ciscn 2022 东北赛区]math

1.题目 import gmpy2 from Crypto.Util.number import * from flag import flag assert flag.startswith(b"flag{") assert flag.endswith(b"}") messagebytes_to_long(flag) def keygen(nbit, dbit):if 2*dbit < nbit:while True:a1 getRandomNBitIn…

编辑器目录树的设计,一点也不简单

朋友们好&#xff0c;我是优秀的大鹏 今天花了很长时间思考一个网页文档编辑器&#xff0c;云端目录树要怎么设计 这个看似简单的需求&#xff0c;技术上和产品上的思考却非常复杂 下面以几种编辑器为例&#xff0c;讲一下各种编辑器在技术上和产品的思考 1、以Vscode为代表的本…

Delphi DataSet转JSon (使用SuperObject)

Delphi中将TDataSet转换为JSon字符串。 with ATM.LoadDataSet() dobeginif IsEmpty thenbeginLogObj.WriteLog(未查询到该视图名称下该时间段内的上传数据&#xff0c;视图名称&#xff1a; AViewname 开始时间&#xff1a; AStartdate 结束时间&#xff1a; AEnddate);exit…

【神经网络与深度学习】Transformer原理

transformer ENCODER 输入部分 对拆分后的语句x [batch_size, seq_len]进行以下操作 Embedding 将离散的输入&#xff08;如单词索引或其他类别特征&#xff09;转换为稠密的实数向量&#xff0c;以便可以在神经网络中使用。位置编码 与RNN相比&#xff0c;RNN是一个字一个字…

Django Rest Framework 全局异常处理

在Django Rest Framework&#xff08;DRF&#xff09;中&#xff0c;全局异常处理是一种重要的机制&#xff0c;它可以帮助我们更好地管理API中的异常情况&#xff0c;并返回统一的错误响应。本文将详细介绍两种全局异常处理的方法&#xff1a;使用中间件&#xff08;Middlewar…

机器学习(3)

目录 3-1线性回归 3-2最小二乘解 3-3多元线性回归 3-4广义线性模型 3-5对率回归 3-6对率回归求解 3-7线性判别分析 3-8LDA的多类推广 3-9多分类学习基本思路 3-10类别不平衡 3-1线性回归 线性模型为什么重要&#xff1f; 人类在考虑问题时&#xff0c;通常…

用python写一个自动生成android开机动画的工具

要创建一个自动生成Android开机动画的工具&#xff0c;你需要一些基本的知识&#xff0c;比如Python编程、图像处理和Android开机动画的格式。以下是一个简单的Python脚本示例&#xff0c;它可以生成一个基本的Android开机动画&#xff0c;具体效果可能需要更多的调整和优化。 …

记录glide加载图片,设置圆角

支持所有角的圆角&#xff0c;自动计算合适的半径&#xff0c;不用担心图片比预定值小导致的圆角过大的问题 修改自&#xff1a;https://blog.csdn.net/qq_15059163/article/details/97613790 增加了指定图片尺寸、解决了图片某些情况下圆角过大的问题 public class GlideRou…

先有JVM还是先有垃圾回收器?很多人弄混淆了

是先有垃圾回收器再有JVM呢&#xff0c;还是先有JVM再有垃圾回收器呢&#xff1f;或者是先有垃圾回收再有JVM呢&#xff1f;历史上还真是垃圾回收更早面世&#xff0c;垃圾回收最早起源于1960年诞生的LISP语言&#xff0c;Java只是支持垃圾回收的其中一种。下面我们就来刨析刨析…

外卖系统的JWT实现登录

1、什么是JWT jwt可以生成一个加密的token&#xff0c;作为用户登录的令牌&#xff0c;当用户登陆成功之后&#xff0c;发放给客户端。请求需要登录的资源或者接口的时候&#xff0c;将token携带&#xff0c;后端验证token是否合法。jwt有三部分组成&#xff1a; A&#xff1a;…

【特大喜讯】国内前33位持有PMI-RMP风险管理专业认证的学员分享~!

【学员背景】 沈阳某信息科技有限公司&#xff0c;从事企业采购供应链数字化转型方向&#xff1b; 为企业提供有效的降本增效解决方案。 【学员顺利拿证后期访问】 问&#xff1a;学员您好&#xff0c;首先恭喜您顺利拿到RMP证书&#xff0c;请问您在此次备考过程中&#xf…

抖店商品详情API接口(产品参数|详情图)

抖店商品详情API接口(产品参数|详情图) 参数仅供参考&#xff1a; {"code": 0,"msg": "调用成功","time": "1715763239","data": {"properties": [{"format": [{"message": [{&q…

C语言简要(一)

总得让她开心吧 helloworld #include <stdio.h>int main() {printf("hello world!\n");return 0; } 程序框架 #include <stdio.h> int main {return 0; }输出 printf("hello world!\n"); "里面的内容叫做“字符串”&#xff0c;prin…

BUUCTF靶场[MISC]wireshark、被嗅探的流量、神秘龙卷风、另一个世界

[misc]wireshark 考点&#xff1a;流量、追踪流 工具&#xff1a;wireshark 先看题目&#xff0c;管理员密码 将下载的文件用wireshark打开&#xff0c;查找flag 点击追踪tcp流&#xff0c;开始挨个查看flag [misc]被嗅探的流量 考点&#xff1a;流量、追踪流 工具&#xf…