Fortran笔记,指针-Part1
参考:彭国伦:《Fortan 95程序设计》,第10章,2002年
指针最简单的应用可以用来保存变量,或者是动态使用内存。更进一层则可以应用在特别的“数据结构”上,例如创建“串行结构”、“树状结构”等等。
目录:
- 指针的基本概念
- 指针数组
- 指针与函数
- 指针的基本应用
- 指针的高级应用
- 单向串行
- 双向串行、环状串行
- 插入及删除
- 串行的应用
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相关推荐
- 【学习笔记】Part1·JavaScript·深度剖析-函数式编程与 JS 异步编程、手写 Promise(二、JavaScript 异步编程)
[学习笔记]Part1·JavaScript·深度剖析-函数式编程与 JS 异步编程.手写 Promise(课前准备) [学习笔记]Part1·JavaScript·深度剖析-函数式编程与 JS 异步 ...
- C语言学习笔记——指针章节
学习小结 c语言指针学习笔记汇总 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h>//指针 //在计算机科学中,指针是编程语言的一个对 ...
- c语言普通变量间接访问,C语言学习笔记-指针
野指针问题 野指针是没有指向地址的指针,也就是该指针指向的地址是随机的. 因为指针的指向地址是随机的,所以很有可能指向不可访问的弟子,导致程序崩溃,或者访问了不该访问的地址,导致影响其他功能使用 为了 ...
- go语言笔记——指针,和C用法以及本质一样,但不支持指针的+-运算!
4.4.2 值类型和引用类型 所有像 int.float.bool 和 string 这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值. Go 语言的取地址符是 &,放到一个 ...
- C++笔记——指针函数/函数指针
两者主要区别,一个是函数(指针函数),一个是指针变量(函数指针). 指针函数 (1)定义 指针函数:顾名思义就是带有指针的函数,即其本质是一个函数,只不过这种函数返回的是一个对应类型的地址. (2) ...
- C++笔记——指针数组/数组指针
1.定义 指针数组:array of pointers,即用于存储指针的数组,也就是数组元素都是指针.定义 int *p[n]; 数组指针:a pointer to an array,即指向数组的指针 ...
- C语言学习笔记---指针和数组
数组是相同类型的数据集合,会在内存中占用连续的一块内存.而指针是存储的一个地址,在内存中不会占用连续的内存. 先来写一段测试代码 void fun(void) {int i;int num[10]={ ...
- C语言学习笔记---指针
C语言要玩的好,指针是核心,但是指针在学习的时候看教程往往感觉一看就明白,但是实际用的时候一用就错,而且还不知道错在哪.为了更加深刻的了解指针,将学习过程记录下来,依次加深对指针的理解. 先看看一段测 ...
- 学习笔记——指针那些事儿
指针概况 关于指针这一块儿,学起来容易迷,当然也是C语言的重点.下面详细说说指针的类. 指针是特殊的变量,相当于地址,指针里面存储的数据数值实际上就是内存地址.需要考虑四个方面:指针的类型,指针所指的 ...
最新文章
- 找出数组中出现次数超过一半的数
- echarts实现柱状图分页展示
- kettle读取json文件并读取数据_Labview打开Excel文件读取数据
- Elementui select 设置点击事件,在Change事件前触发
- sudo gedit出现No protocol specified
- windows无法确定此计算机是否包含,服务器用U盘虚拟光驱装系统,有做RAID5,加载RAID驱动成功后,安装到最后会报“windows无法确定此计算机是否包含有效系统卷”错误...
- 老码农:这段代码绝了,切勿模仿!
- mysql-修改密码(error-1290 (HY000): The MySQL server is running with the --skip-grant-tables option so)
- mysql作业是什么意思_MySQL 作业七
- mysql2 0.3.16.gem_安装mysql2时出错:无法构建gem原生扩展
- 使用jdk的xjc命令由schema文件生成相应的实体类
- 连接好友服务器失败 无法显示,不显示好友的网络状态
- Bootstrap 模态框(Modal)插件
- mybaties中的selectKey和useGeneratedKeys=true
- python 爬取种子_Python开发实例分享bt种子爬虫程序和种子解析
- Superl-url:一款开源关键词URL采集工具
- vue-i18n的入门使用
- 组装计算机必须要有显卡吗,组装电脑应该侧重CPU还是显卡
- sql 求和并且将求和条件作为查询条件
- 2021年职业院校技能大赛“网络安全”项目江西省A模块