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.hqwc.cn/news/704390.html

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

相关文章

第9章.Keil5-MDK软件简介

目录 0. 《STM32单片机自学教程》专栏 9.1 主界面 9.2 文本格式编辑 9.3 代码提示&语法检测&代码模版 9.4 其他小技巧 9.4.1 TAB 键的妙用 9.4.2 快速定位函数/变量被定义的地方 9.4.3 快速注释与快速消注释 9.4.4 快速打开头文件 9.4.5 查找替换…

数据结构初阶 顺序表的补充

一. 题目的要求 写出三种链表的接口函数 它们的功能分别是 1 查找数的位置 2 在pos位置插入值 3 在pos位置删除值 二. 实现pos 这个其实很简单 找到一步步遍历 找到这个数字就返回 找不到就提示用户下 这个数字不存在 int SLFind(SL* ps,SLDateType x) {assert(ps);int…

醉了,面个功能测试,还问我Python装饰器

Python 装饰器是个强大的工具,可帮你生成整洁、可重用和可维护的代码。某种意义上说,会不会用装饰器是区分新手和老鸟的重要标志。如果你不熟悉装饰器,你可以将它们视为将函数作为输入并在不改变其主要用途的情况下扩展其功能的函数。装饰器可…

[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…

(实测验证)【移远EC800M-CN 】TCP 透传

引言 本文章使用自研“超小体积TTL转4GGPS集成模块”进行实测验证&#xff1b; 1、配置移远EC800M-CN TCP 透传 串口助手发送&#xff1a; ATQIOPEN1,0,"TCP","36.137.226.30",39755,0,2 //配置服务器地址和端口号&#xff1b; 4G模组返回…

Go微服务: 接入Prometheus性能监控平台与Grafana平台

接入Prometheus 在 go-micro 生成的模板中, 我们一如既往的完成基础工作之后 进入main.go工作的代码编写&#xff0c;main.go package mainimport ("fmt""log""strconv""github.com/go-micro/plugins/v4/registry/consul"opentracing…

MaxKB创建本地知识库

上节已经可以通过MaxKB创建简单的问答系统了&#xff0c;这节开始做自己的知识库&#xff0c;实际上就是把一些本地文件上传到大模型中&#xff0c;让大模型学会这些文件内容&#xff0c;你在问他问题的时候可以通过此文件的内容来回答你&#xff0c;尤其是在针对特定场景或者特…

(实测验证)Gitee代码托管尝试(一)——克隆/下载

一、登录 Gitee&#xff08;码云&#xff09;代码托管平台&#xff1a; Gitee - 基于 Git 的代码托管和研发协作平台 新建个人账户如下&#xff1a; 二、SSH 公钥设置 1、在git安装目录打开“git-cmd.exe”; 2、通过命令 ssh-keygen 生成 SSH Key&#xff1a; ssh-keygen …

指针在函数的应用(C++)

一、传递地址 实参传递进函数体内后&#xff0c;生成的是实参的副本&#xff0c;在函数内改变副本的值并不影响实参。指针传递参数时&#xff0c;指针变量产生了副本&#xff0c;但副本与原变量指向的内存区域是同一个。改变指针副本指向的变量&#xff0c;就是改变原指针变量指…

网络安全 会飞的狗狗 网络安全狗是什么

1.概述 网站安全狗是一款集网站内容安全防护、网站资源保护及网站流量保护功能为一体的服务器工具。功能涵盖了网马/木马扫描、防SQL注入、防盗链、防CC攻击、网站流量实时监控、网站CPU监控、下载线程保护、IP黑白名单管理、网页防篡改功能等模块。能够为用户提供实时的网站安…

做简单易用的GIS资源管理软件

在室外资源管理领域&#xff0c;采用基于GIS的解决方案已成为主流趋势&#xff0c;旨在实现资源的高效利用和管理。GIS技术结合资源对象的规划、定位和监控&#xff0c;为企业提供全面的管理方案&#xff0c;从而优化资源使用、提高运营效率和降低成本。 然而&#xff0c;许多资…

ROS 手眼标定 realsense435i+ur5e

手眼标定的原理 基坐标系&#xff08;base_tree&#xff09;和相机&#xff08;camera_tree&#xff09;两个坐标系属于不同的tree&#xff0c;通过将标签贴到手上&#xff0c;相机识别出标签的position和orention&#xff0c;并通过easy_handeye标定包得到tool0(机械手)&…