参考:彭国伦:《Fortan 95程序设计》,第10章,2002年

指针最简单的应用可以用来保存变量,或者是动态使用内存。更进一层则可以应用在特别的“数据结构”上,例如创建“串行结构”、“树状结构”等等。

目录:

  1. 指针的基本概念
  2. 指针数组
  3. 指针与函数
  4. 指针的基本应用
  5. 指针的高级应用
    1. 单向串行
    2. 双向串行、环状串行
    3. 插入及删除
    4. 串行的应用

1. 指针的基本概念

指针变量用来保存一个“内存地址”,当程序读写指针变量时,实际上会经过两个步骤:

(1)取出指针中所保存的内存地址;

(2)到这个内存地址读写数据。

指针变量中所保存的内存地址来源可以有两种:

(1)记录其他非指针变量的内存地址;

(2)程序执行中动态配置的一块内存。

实例1:通过指针访问所指向的变量

    ! 指针的简单使用,访问、修改所指向的变量subroutine pointer_visit()implicit noneinteger, target :: a = 1    ! 可被指针指向的整型变量integer, target :: b = 9999integer, pointer :: pa      ! 可指向整型的指针变量pa => a     ! 将指针指向整型变量! 通过指针变量访问其指向的变量,包含两步! step 1: 通过指针变量所存储的地址访问内存 ! step 2: 获得该内存中的内容(依赖所定义的指针类型)write(*,*) pa! 修改整型变量,对指针进行解析的结果相应发生变量! 实际为step 2结果不同,指针所存储的地址并未变化a = 2write(*,*) pa! 通过指针变量修改所指向的变量pa = 3write(*,*) a! 把指针重新指向别的整型变量,bpa => bwrite(*,*) bend subroutine pointer_visit

输出结果为:

           1239999

实例2:通过指针动态配置内存

    ! 通过指针动态配置内存subroutine pointer_dynamic()implicit noneinteger, pointer :: paallocate(pa)    ! 配置一块可以存放整型的内存空间给指针papa = 10         ! 该内存空间存储的是整数10write(*,*) pa   ! 访问指针所指向的内存的存储内容deallocate(pa)  ! 释放该动态内存空间end subroutine pointer_dynamic

要点:

1. 函数allocate可用来配置内存空间给可变大小的数组使用(定义数组时须使用allocatable来修饰),此处案例表明allocate还可用来配置一块内存空间给指针使用,并将该内存的地址存放在指针p中。

2. 指针是变量,可重新设置它的指向(如实例1中所示)。但通过allocate指向内存的指针在重定向前,需通过deallocate将内存释放,否则在程序结束前,仍占计算机的内存。

???使用动态内存的场景???

注意:

使用指针前,一定要先设置好指针的目标。

否则,在Windows系统下可能会先死一堆内存地址,显示内存读写不正常的信息。在UNIX系统下会出现Segmentation fault的错误信息。

示例代码:

...
integer, pointer :: pb
write(*,*) pb
...

编译时并不会进行指针未指向的检查,但是在运行时的显示错误信息:

引发了异常: 读取访问权限冲突。
**PB** 是 0xCCCCCCCC。

Fortran提供ASSOCIATED, NULLFY, NULL等函数来完善对未指向的指针的检测、处理。

ASSOCIATED(pointer, [target])

检查指针pointer是否设置指向(如果输入两D个变量则为是否指向target),返回值为布尔变量。

NULLIFY(pointer1, [pointer2, ...])

用来把指针设置成还没指向任何内存地址。

NULL()

返回一个不能使用的内存地址,用来对指针初始化。Fortran 95添加的。

NULLIFY及NULL函数是为了确保ASSOCIATED函数不会出错,?即意味着未使用NULLIFY和NULL函数的情况下,即使指针未指向,ASSOCIATED也可能判断为已经指向某个内存了?与编译器和操作系统有关? <== 见下例,未明确为空指针,判断结果为TRUE

启示:使用指针时,应使用NULL,NULLIFY初始化

示例:

    ! 测试ASSOCIATED, NULLIFY, NULL函数subroutine pointer_null()implicit noneinteger, target :: a = 10integer, pointer :: pa  integer, pointer :: pb => null()    ! 初始化指针为空指针! 未明确指向的指针, Twrite(*,*) associated(pa)nullify(pa)! 明确为空指针, Fwrite(*,*) associated(pa)! 指向整型变量的指针, Tpa => a write(*,*) associated(pa)! 明确为空指针, Fwrite(*,*) associated(pb)end subroutine pointer_null

输出结果为:

 TFTF

是否使用NULL, NULLIFY的区别如下,断点设置在变量声明结束后:

指针可以声明成任何数据类型,甚至是使用TYPE自定义的数据类型。但无论指针指向哪一种数据类型,指针变量所占用的的内存空间均相同。比如:在32位机器上,记录一个内存地址,固定需要使用32 bits = 4 bytes的空间。


2. 指针数组

指针可指向数组,也称为指针数组。

实例1:通过指针访问数组

    ! 指向数组的指针subroutine pointer_array1()implicit noneinteger, target :: a(5)=(/1, 2, 3, 4, 5/)integer, pointer :: pa(:)   ! 指向数组的指针声明时只需明确维数! 数组指针pa指向数组apa=>awrite(*,*) pa! 数组指针pa指向数组的部分apa=>a(1:3)write(*,*) papa=>a(1:5:2)write(*,*) papa=>a(5:1:-1)write(*,*) paend subroutine pointer_array1

输出结果为:

           1           2           3           4           51           2           31           3           55           4           3           2           1

思考一个问题:

为何可以指向数组的一部分?

数组指针pa所存储的应该不止是数组a的地址,还应当包括依据该地址所进行解析的顺序,比如5:1:-1;亦或是存储的是一串地址?但这样似乎不符合上一节所说的,即指针变量大小相同。

实例2:通过指针动态分配内存以存储数组

注意,在声明多维数组是,若附加了TARGET属性,数组大小必须明确,否则编译错误。

声明如下:

integer, target :: array_3d(:,:,:) ! 3维数组

编译错误提示如下:

error #6596: If a deferred-shape array is intended, 
then the ALLOCATABLE or POINTER attribute is missing; 
if an assumed-shape array is intended, 
the array must be a dummy argument.   [ARRAY_3D]

大意为:

若想要一个延迟定型(deferred-shape)的数组,ALLOCATABLE或POINTER属性必不可少;

若想要一个确定大小(assumed-shape)的数组,数组必须是哑元参数(dummy argument)。

故使用TARGET属性时,应当明确数组大小。

实例2:通过指针动态开辟内存空间

    ! 通过指针动态开辟内存以存储数组subroutine pointer_array2()implicit noneinteger, pointer :: pa_1d(:)        ! 1维指针数组integer, pointer :: pa_2d(:,:)      ! 2维指针数组integer, pointer :: pa_3d(:,:,:)    ! 3维指针数组integer, target :: array_3d(4,3,2)  ! 3维数组integer :: index_i! 开辟内存时应当明确数组大小(维数不变)allocate(pa_1d(3))pa_1d = (/1, 2, 3/)write(*,"(3I2,/)") pa_1ddeallocate(pa_1d)   ! 使用完毕,应当释放内存forall(index_i=1:3)array_3d(:,index_i,1) = index_iarray_3d(:,index_i,2) = index_i+3end forallwrite(*, "( 2( 3(4I2,/), / ) )") array_3d! pa_2d指向array_3d的部分,一个4*3的二维数组pa_2d=>array_3d(:,:,1)write(*, "(3(4I2,/))") pa_2d! pa_2d指向array_3d的部分,一个2*3的二维数组pa_2d=>array_3d(1:4:2,:,1)write(*, "(3(2I2,/))") pa_2d! pa_3d指向array_3d的部分,一个3*3*2的三维数组pa_3d=>array_3d(1:3,1:3,1:2)write(*, "(2(3(3I2,/),/))") pa_3dend subroutine pointer_array2

输出结果为:

 1 2 31 1 1 12 2 2 23 3 3 34 4 4 45 5 5 56 6 6 61 1 1 12 2 2 23 3 3 31 12 23 31 1 12 2 23 3 34 4 45 5 56 6 6

ALLOCATABLE数组 vs 指针数组

ALLOCATABLE数组在函数结束时(比如在某个函数中定义),自动DEALLOCATE;

而指针数组(此处说的是pa_1d这种情况),除非代码显式的DEALLOCATE,否则一直存在于内存中(?函数之外如何访问呢?浪费内存)


3. 指针与函数

按书上所介绍的,使用interface较为繁琐,跳过,直接使用module封装,

module funccontains! 寻找最小数! 参数:p为指针! 函数的返回为指针function getmin(p)implicit noneinteger, pointer :: p(:)integer, pointer :: getmin! local variableinteger :: index_i, length_i, min_i! 初始化指针getmin => null()! 获取指针数组的长度length_i = size(p,1)! 给定min_i的初值min_i = p(1)! 遍历指针数组do index_i = 1, length_iif( p(index_i)<min_i ) thenmin_i = p(index_i)getmin => p(index_i)end ifend doend function getminend module funcprogram Chapter10use funcimplicit none! Variablesinteger, target :: a(5) = (/9, 10, 4, 88, -1/)integer, pointer :: pa(:)! use module func !pa => awrite(*, "('The min of', 5I5, ' is:', /, I2)") pa, getmin(pa)stopend program Chapter10

输出结果为:

The min of    9   10    4   88   -1 is:
-1

Fortran笔记,指针-Part1相关推荐

  1. 【学习笔记】Part1·JavaScript·深度剖析-函数式编程与 JS 异步编程、手写 Promise(二、JavaScript 异步编程)

    [学习笔记]Part1·JavaScript·深度剖析-函数式编程与 JS 异步编程.手写 Promise(课前准备) [学习笔记]Part1·JavaScript·深度剖析-函数式编程与 JS 异步 ...

  2. C语言学习笔记——指针章节

    学习小结 c语言指针学习笔记汇总 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h>//指针 //在计算机科学中,指针是编程语言的一个对 ...

  3. c语言普通变量间接访问,C语言学习笔记-指针

    野指针问题 野指针是没有指向地址的指针,也就是该指针指向的地址是随机的. 因为指针的指向地址是随机的,所以很有可能指向不可访问的弟子,导致程序崩溃,或者访问了不该访问的地址,导致影响其他功能使用 为了 ...

  4. go语言笔记——指针,和C用法以及本质一样,但不支持指针的+-运算!

    4.4.2 值类型和引用类型 所有像 int.float.bool 和 string 这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值. Go 语言的取地址符是 &,放到一个 ...

  5. C++笔记——指针函数/函数指针

    两者主要区别,一个是函数(指针函数),一个是指针变量(函数指针). 指针函数 (1)定义 指针函数:顾名思义就是带有指针的函数,即其本质是一个函数,只不过这种函数返回的是一个对应类型的地址. (2) ...

  6. C++笔记——指针数组/数组指针

    1.定义 指针数组:array of pointers,即用于存储指针的数组,也就是数组元素都是指针.定义 int *p[n]; 数组指针:a pointer to an array,即指向数组的指针 ...

  7. C语言学习笔记---指针和数组

    数组是相同类型的数据集合,会在内存中占用连续的一块内存.而指针是存储的一个地址,在内存中不会占用连续的内存. 先来写一段测试代码 void fun(void) {int i;int num[10]={ ...

  8. C语言学习笔记---指针

    C语言要玩的好,指针是核心,但是指针在学习的时候看教程往往感觉一看就明白,但是实际用的时候一用就错,而且还不知道错在哪.为了更加深刻的了解指针,将学习过程记录下来,依次加深对指针的理解. 先看看一段测 ...

  9. 学习笔记——指针那些事儿

    指针概况 关于指针这一块儿,学起来容易迷,当然也是C语言的重点.下面详细说说指针的类. 指针是特殊的变量,相当于地址,指针里面存储的数据数值实际上就是内存地址.需要考虑四个方面:指针的类型,指针所指的 ...

最新文章

  1. 找出数组中出现次数超过一半的数
  2. echarts实现柱状图分页展示
  3. kettle读取json文件并读取数据_Labview打开Excel文件读取数据
  4. Elementui select 设置点击事件,在Change事件前触发
  5. sudo gedit出现No protocol specified
  6. windows无法确定此计算机是否包含,服务器用U盘虚拟光驱装系统,有做RAID5,加载RAID驱动成功后,安装到最后会报“windows无法确定此计算机是否包含有效系统卷”错误...
  7. 老码农:这段代码绝了,切勿模仿!
  8. mysql-修改密码(error-1290 (HY000): The MySQL server is running with the --skip-grant-tables option so)
  9. mysql作业是什么意思_MySQL 作业七
  10. mysql2 0.3.16.gem_安装mysql2时出错:无法构建gem原生扩展
  11. 使用jdk的xjc命令由schema文件生成相应的实体类
  12. 连接好友服务器失败 无法显示,不显示好友的网络状态
  13. Bootstrap 模态框(Modal)插件
  14. mybaties中的selectKey和useGeneratedKeys=true
  15. python 爬取种子_Python开发实例分享bt种子爬虫程序和种子解析
  16. Superl-url:一款开源关键词URL采集工具
  17. vue-i18n的入门使用
  18. 组装计算机必须要有显卡吗,组装电脑应该侧重CPU还是显卡
  19. sql 求和并且将求和条件作为查询条件
  20. 2021年职业院校技能大赛“网络安全”项目江西省A模块

热门文章

  1. HadoopSourceAnalyse --- NodeManager -- initiate
  2. python中用Selenium驱动Edge浏览器的方法
  3. vue打开其他项目的页面/打开外部链接,window模态框或内嵌在项目里
  4. 恭喜HBuilderX用户
  5. HPUNIX环境常用查看硬件设备信息命令小结
  6. vue(emit)、node(promise、 promise封装文件读取)
  7. Windows SVN迁移实操笔记
  8. 02.Linux的基础命令
  9. Android NSD学习与使用
  10. Virtual box中win7分辨率问题解决