Skip to content

Latest commit

 

History

History
139 lines (84 loc) · 6.56 KB

Fortran基础篇03:第一把利器.md

File metadata and controls

139 lines (84 loc) · 6.56 KB

Fortran基础篇03:第一把利器

如果上一章的分支和循环是剑谱,那这一章要讲的数组就是你的宝剑了(前面说的单个变量顶多是个小石子儿),还不赶紧练练人剑合一:smirk:

数组的概念想必大家都能理解,高中学的数列,大学学的矩阵,都有数组的影子。以前农村各家各户爱住哪儿住哪儿,这些年实施新农村建设,大家都搬到一块儿,房子做的是一排一排的。这跟内存中的单个变量与数组变量有点类似,内存就像这广袤的农村大地,变量就像每家每户的房子,单个变量一会儿村头一会儿村尾,想找到他们家就得有个确切的地址,而数组变量就比较集中,要么路边摆一排,要么竖起来一栋,然后数门牌号就行。对于住户来说好像没什么变化,但对于收电费的来说感觉就老好了(虽然现在也不用上门收电费:smiley:)。

废话之后上代码,看看Fortran中的数组是怎么定义的:

INTEGER, DIMENSION(6)::vi  !定义整型数组vi,里面包含6个整数
REAL, DIMENSION(8)::vr     !定义实型数组vr,里面包含8个实数

是不是so easy(妈妈再也不用……)。数组变量跟单个变量一样,也是有类型的,唯一不同的是单个变量只能装一个值,而数组变量可以装好多个值,好多个是多少就看你怎么定义了。DIMENSION是Fortran的一个关键字,用于声明数组的大小(或尺寸),字面意思很明确。早期代码可能没有DIMENSION,但也声明了数组,如下所示:

INTEGER::vi(6)  !定义整型数组vi,里面包含6个整数
REAL::vr(8)     !定义实型数组vr,里面包含8个实数

这两种声明形式是等价的,但新代码中推荐使用DIMENSION版,一目了然能减少犯错机率,搜索DIMENSION关键字也能帮你快速定位哪些是数组,哪些不是。

声明好数组变量以后该给它赋值了,然后就可以愉快地玩耍。那么问题来了,单个变量赋一个值就完了,数组一来一大堆好怕怕:joy:?兵来将挡,水来土掩,来一堆就赋一堆。Fortran中有个数组构造器,看示例:

INTEGER, DIMENSION(6)::vi
vi = (/ 1, 2, 3, 4, 5, 6 /)  !构造6个整数的数组并赋给vi

你又想问,100个怎么整?难道从1写到100?编程是省事的,不是找麻烦的,Fortran中有个隐式DO循环,专治这种疑难杂症。

INTEGER::i    !循环变量
INTEGER, DIMENSION(100)::vi
vi = (/ (i, i = 1, 100) /)  !构造100个整数的数组并赋给vi

你可能觉得这功能太简单了,鸡肋鸡肋,那就玩点花样吧

INTEGER::i, j    !循环变量
INTEGER, DIMENSION(100)::vi
vi = (/ ((i, i = 1, 8), 0, j * 10 ,j = 1, 10) /)  !猜猜我是啥

注意,构造出来的数组中的元素个数要与数组变量的大小一致,否则编译不通过。如果不用数组构造器,直接用单个值进行赋值,那么数组变量的所有元素都等于该值。


上述隐式DO循环也可以用显式DO循环写出来,只不过显式DO循环要多写几行

INTEGER::i    !循环变量
INTEGER, DIMENSION(100)::viDO i = 1, 100  vi(i) = iEND DO

上例中vi(i)表示vi数组中的第i个元素,这种获数组中元素的方式称为下标索引。索引的下标不能越界,如上例中定义的vi大小是100,下标就从1到100,超过这个范围的索引将产生不确定的错误结果。

你可能又想找茬,为什么要从1开始,C/C++不是从0开始的吗,从C/C++切换过来怎么办?看代码

INTEGER::i    !循环变量
INTEGER, DIMENSION(0:99)::vi
DO i = 1, 100  
	vi(i - 1) = i
END DO

不想用默认的下标范围,可以在DIMENSION中定义下标的上下界。Fortran甚至做的更绝,负下标都能接受

INTEGER::i    !循环变量
INTEGER, DIMENSION(-50:50)::vi  !现在我能装101个了
DO i = -50, 50    
	vi(i) = i + 50
END DO

索引一个元素算啥,索引一堆才算本事,指哪儿索哪儿,索出来还能赋值操作,是不是很方便:smirk:这一点C/C++是没法比的,毕竟Fortran才是数值计算科班出身。

INTEGER, DIMENSION(100)::vi
vi(:)      !索引整个数组
vi(3:)     !索引从第3到最后一个元素
vi(:3)     !索引从第1到第3个元素
vi(3:50)   !索引从第3到第50个元素
vi(3:50:3) !索引第369、……、48号元素

上述索引方式(i:j:k)称为下标三元组,i表示起始下标,j表示终止下标,k表示下标变化的步长,默认步长为1。这种索引方式经常被使用,相比单个元素的索引,下标三元组索引能减少DO循环的使用,使代码更加简洁高效。

数组能用来干嘛呢?前面说了,数组是你的宝剑,而不是小石子儿。实际工作中经常遇到大批量数据,要在程序中保存和处理这些数据肯定不可能一个一个变量去定义,数组就可以派上用场了,具体的用途可在今后的代码中慢慢体会。

到这儿数组的核心内容介绍得也差不多了,知道怎么定义,怎么索引,再配上DO循环就可以干很多事了,更高级的多维数组、动态数组等留到进阶篇中讲解。下面说说跟数组比较接近的字符串

字符串可以看作字符数组,但字符串的定义和使用跟数组略有不同。

CHARACTER(10)::str  !包含10个字符的字符串
str='1234567890'    !赋值
WRITE(*,*) str(3:3) !将输出3
WRITE(*,*) str(3:5) !将输出345
WRITE(*,*) str(:3)  !将输出123
str = str(1:3)//str(6:8)  !字符串拼接,str将变成123678

索引字符串中的子串时和数组的索引一致,但索引单个元素时,数组可以用单数字下标,而字符串必须用冒号形式的下标,这是需要注意的地方。字符串也可以当作普通变量而定义成一个数组,例如:

CHARACTER(10), DIMENSION(5)::strs !包含5个字符串,每个字符串包含10个字符
...
str(2)(3:5)  !索引第2个字符串元素的第35个字符子串

Fortran是为数值计算而生的,对于数值相关的操作(尤其是矩阵操作)支持得很好,而字符串的处理不是它的强项。因此使用Fortran时只涉及最基本的字符处理,不用在这方面下太多工夫。关于数组之间的运算操作及其它琐碎知识可参考推荐教材

下一章将为大家介绍Fortran函数及模块方面的知识,敬请期待:wink: