fortran プログラミング 第11 12 回...
TRANSCRIPT
木村拓馬
FORTRANプログラミング–第 11・12回 ポインタとリスト構造–
木村拓馬
2014年12月 16日 21:43
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 1/25
木村拓馬
ポインタ.ポインタ..
......
Fortran90で新しく導入された機能
データポインタ: 他の変数を指す変数
(手続ポインタ: 他の手続(関数・サブルーチン)を指す手続)
.
...... ここではデータポインタのみ扱う
.データポインタ..
......
他の変数と結合する(指す)と,その変数の別名のように使える
配列や構造体,それらの一部も指せる
構造体と組み合わせてリスト構造を作ったり(次回)
12.4.6ポインタ [1] データポインタ (data pointer)は,POINTER属性をもつデータ要素とする。手続ポインタ (procedure pointer) は,POINTER属性をもつ
手続要素とする。ポインタ (pointer)は,データポインタ又は手続ポインタのいずれかとする。ポインタは,ポインタ代入(7.4.2参照)によって指示先 (target)
と結合されて指示状態 (pointer associated)になる。データポインタは,割付け(6.3.1参照)によって指示先と結合されて指示状態になってもよい。ポインタ
は,NULLIFY 文の実行の結果として,空状態のポインタとのポインタ代入の結果として,暗黙的初期値指定によって,又は明示的初期値指定によって空状態
(disassociated)になる。データポインタは,DEALLOCATE文の実行によっても,空状態 (disassociated)になることがある。空状態のポインタは,指示先と結
合していない(16.4.2参照)。結合していないポインタは,引用も確定もしてはならない。データポインタが配列であるときは,次元数は宣言されるが,寸法は
そのポインタが指示先と結合した時に決まる。
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 2/25
木村拓馬
.ポインタの使い方..
......
ポインタの宣言....... 型,POINTER :: ポインタ変数名または配列名,…
.
......例) integer, pointer :: p
例) integer, pointer :: p(:) ⇐大きさは無指定で宣言する.
TARGET属性を指定した変数の宣言....... 型,TARGET :: 変数名
.
......例) integer, target :: a
例) integer, target :: a(3) ⇐大きさを指定してもよい.
ポインタと TARGET属性をもつ変数との結合....... ポインタ変数名 => TARGET 属性をもつ変数名(またはポインタ変数名)
.
......例) p => a
ポインタは宣言しただけではどこも指してない
ポインタが指せるのは,
同じデータ型で,
TARGET属性をもつ変数,ポインタ
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 3/25
木村拓馬
.ポインタの宣言,結合 (ex11.1.f90) .. Download
..
......
1 program pointer1
2 implicit none
3 !ポインタの宣言
4 integer, pointer :: p
5 !TARGET 属性を指定した変数の宣言
6 integer, target :: a
7 !ポインタと TARGET 属性をもつ変数との結合
8 p => a
9 !ポインタは結合した変数の別名として使える
10 p = 10
11 write(*,*) a
12 p = p + 10
13 write(*,*) a
14 end program pointer1.実行すると(pの値を変えると aの値が変わる)..
......10
20
ポインタは他の変数と結合する(指す)と,その変数の別名のようにして代入文や式に
書くことができる.
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 4/25
木村拓馬
.例:結合しなおすことができる (ex11.2.f90) .. Download
..
......
1 program pointer2
2 implicit none
3 integer, pointer :: p1, p2
4 integer, target :: a1, a2
5 p1 => a1; p2 => a2
67 p1 = 10; p2 = 20
8 write(*,*) a1,a2,p1,p2
9 p2 => a1
10 p1 = p1+1; p2 = p2+2
11 write(*,*) a1,a2,p1,p2
12 end program pointer2
⇓
.実行すると(a1,a2,p1,p2の値が変わる)..
......10 20 10 20
13 20 13 13
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 5/25
木村拓馬
ポインタは配列を扱うこともできる.ただし,
配列へのポインタであることを明示的に宣言すること(p(:)).
大きさは無指定で宣言すること((:))..例:配列を指すポインタ (ex11.3.f90) .. Download
..
......
1 program pointer3
2 implicit none
3 integer, pointer :: p(:)
4 integer, target :: a(3)
5 p => a
6 p(1) = 1
7 p(2) = 2
8 p(3) = 3
9 write(*,*) a
10 end program pointer3.実行すると........ 1 2 3
ポインタ配列の大きさは,結合した配列の大きさ.ポインタ配列の各要素は,結合した配列の各要素を指す.
2データポインタが配列であるときは,次元数は宣言されるが,寸法はそのポインタが指示先と結合した時に決まる。[1]
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 6/25
木村拓馬
ポインタは構造体を扱うこともできる..例:構造体を指すポインタ (ex11.4.f90) .. Download
..
......
1 program pointer42 implicit none3 type :: record4 character(8) :: id, fname, lname5 integer :: score(3)6 end type record7 character(8), pointer :: p1,p2,p38 integer, pointer :: p4(:)9 type(record), pointer :: p
10 type(record), target :: a11 p => a12 p1 => a%ID13 p2 => a%fname14 p3 => a%lname15 p4 => a%score16 a=record(’1W129999’,’Kimura’,’Takuma’,(/90,100,0/))17 write(*,*) p%id, ’,’, p%fname, ’,’, p%lname, ’,’, p%score18 write(*,*) p1, ’,’, p2, ’,’, p3, ’,’, p419 end program pointer4
.実行すると..
......
1W129999,Kimura ,Takuma , 90 100 0
1W129999,Kimura ,Takuma , 90 100 0FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 7/25
木村拓馬
ポインタはポインタと結合できる..例:ポインタを指すポインタ (ex11.5.f90) .. Download
..
......
1 program pointer5
2 implicit none
3 integer, pointer :: p1, p2
4 integer, target :: a
5 p1 => a
6 p2 => p1
7 p2 = 10
8 write(*,*) a
9 end program pointer5.実行すると(p2の値を変えると aの値が変わる)........ 10
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 8/25
木村拓馬
ALLOCATE文にポインタを入れると,適当な無名の領域と結合する.
このとき,値は不定(g95ではゼロ). ポインタを宣言するときは, ALLOCATABLE属性の指定は必要ない.
DEALLOCATE文でポインタが指す領域を解放.
ポインタは空の状態になり,参照できなくなる..例:結合しなおすことができる (ex11.6.f90) .. Download
..
......
1 program pointer6
2 integer, pointer :: p, q(:)
3 allocate(p, q(10))
4 write(*,*) p, ’/’, q
5 p=1
6 q=2
7 write(*,*) p, ’/’, q
8 deallocate(p,q)
9 ! write(*,*) p !実行するとここでセグメントエラー
10 end program pointer6.実行すると(ALLOCATEすれば普通の変数として使用できる)..
......0 / 0 0 0 0 0 0 0 0 0 01 / 2 2 2 2 2 2 2 2 2 2
3空状態のポインタは,指示先と結合していない(16.4.2参照)。結合していないポインタは,引用も確定もしてはならない。[1]
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 9/25
木村拓馬
.
......
ポインタの結合状態を解除するには....... NULLIFY(ポインタ変数名)
ポインタの結合状態を調べるには....... ASSOCIATE(ポインタ [, 変数名])
.例:結合状態を調べる/結合状態を解除 (ex11.7.f90) .. Download
..
......
1 program pointer7
2 implicit none
3 integer, pointer :: p1,p2
4 integer, target :: a
5 write(*,*) associated(p1)
6 p1 => a
7 write(*,*) associated(p1)
8 p2 => a
9 write(*,*) associated(p1,a), associated(p2,a)
10 nullify(p1)
11 write(*,*) associated(p1,a), associated(p2,a)
12 end program pointer7
.実行すると..
......
F
T
T T
F T
4NULLIFY文(6.3.2参照)は,指示先との結合を解除してポインタを空状態にする。ポインタが不定の結合状態をもたない限り,そのポインタが結合されてい
るか否かは,組込み関数 ASSOCIATED(13.7.13参照)によって知ることができる。[1]
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 10/25
木村拓馬.演習 11.1(pr11.1.f90)..
......
データを値の大きい順に並べ替えるプログラムを作成しよう.
データは,通し番号(3文字の文字列)と整数値が n組.
出力は,並べ替えられた通し番号と整数値.
構造体を利用すること(副プログラムやモジュールは使わなくてもよい).
派生型のポインタを ALLOCATEしてデータを入力・並び替えすること(副プログラムやモジュールは使わなくてもよい).
.データの例..
......
d01, 41
d02, 6
d03, 42
d04, 94
d05, 20
.出力の例..
......
ID, VALUE
d04, 94
d03, 42
d01, 41
d05, 20
d02, 6.選択ソート..
......
1) データ x1, x2, · · · , xn の中での最大値を探し,x1 と入れ替える.
2) データ x2, x3, · · · , xn の中での最大値を探し,x2 と入れ替える...n) データ xn−1, xn の大きい方を xn−1 と入れ替える.
5 ポインタを使う必要は全く無いが,リストの並び替え(次回)の練習のため.
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 11/25
木村拓馬
リスト構造
.リスト構造..
......
データ部とポインタ部からなる構造体を鎖状にポインタで連結するデータ構造
単方向リスト
双方向リスト
循環リスト
単方向リスト
双方向リスト
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 12/25
木村拓馬
リスト構造.リスト構造..
......
データ部とポインタ部からなる構造体を鎖状にポインタで連結するデータ構造
単方向リスト
双方向リスト
循環リスト
循環リスト(単方向)
循環リスト(双方向)
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 13/25
木村拓馬
.リスト構造と配列の違い..
......
リスト構造
利点 ポインタを繋ぎなおすだけでデータを挿入・削除できる.
欠点 データの参照に時間がかかる.
(ポインタをたどり順番に捜査,ランダムアクセスが出来ない)
配列
利点 データの参照が早い.ランダムアクセスができる.
欠点 データの挿入・削除の際,データを格納しなおす手間がかかる.
単方向リストにおけるデータの削除と挿入
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 14/25
木村拓馬
自己参照構造体
リスト構造の,「データ部とポインタ部からなる構造体」の例.
.
......
type record
integer :: dat
type(record), pointer :: next
end type record
例のように,
「自分自身と同じ型(構造体)のポインタを構成要素にもつ構造体」を
「自己参照構造体」という.
ポインタ部が構造体を全て指せるので,リストをつくるとき利用される,6 派生型は,ポインタとして定義された成分を一つ以上もってもよい。その成分が同じ派生型の実体へのポインタであってもよい。この“再帰的”なデータ定
義によって,リスト,木及びグラフのような動的データ構造を構築することができる [1]6 派生型は,ポインタとして定義された成分を一つ以上もってもよい。その成分が同じ派生型の実体へのポインタであってもよい。この“再帰的”なデータ定
義によって,リスト,木及びグラフのような動的データ構造を構築することができる [1]
0
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 15/25
木村拓馬
.リスト構造のつくりかた1..
......
...1 構造体に nextという自分自身を構成要素にもつポインタを追加し,リストの先頭を表すポインタ (root)を設定.
...2 1番目のデータを入力.2番目のデータの記憶領域を確保(allocate).1番目のデータの nextと 2番目のデータを結合(=>).2番目のデータの nextはどことも結合していないものとする(nullify).
...3 2番目のデータを入力.3番目のデータの記憶領域を確保(allocate).2番目のデータの nextと 3番目のデータを結合(=>).3番目のデータの nextはどことも結合していないものとする(nullify).
...4 以下同様.
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 16/25
木村拓馬
.リスト構造のつくりかた2(先頭にダミーノードを置くと,先頭の削除・挿入に便利かも)..
......
...1 構造体に nextという自分自身を構成要素にもつポインタを追加し,リストの先頭を指すだけのポインタ (root)を設定.
...2 1番目のデータの記憶領域を確保し,root%nextと結合(allocate(root%next))1番目のデータの nextはどことも結合していないものとする(nullify).1番目のデータを入力.
...3 2番目のデータの記憶領域を確保し,1番目のデータの nextと結合2番目のデータの nextはどことも結合していないものとする.2番目のデータを入力.
...4 以下同様.
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 17/25
木村拓馬
(例)ex12.1.f90.. Download
root はリストの最初を表す,work は作業ポインタ
リストの最初を表すポインタを設定.
データを入力構造体の記憶領域を確保しnext と結合.新しい構造体の next はどことも結合していないものとする
.リスト構造を作る例(ex12.1.f90)前半..
......
! 例: リスト構造. 単方向リストprogram pointer_list
implicit nonetype record
integer :: dattype(record), pointer :: next
end type record
type(record), pointer :: root, workinteger :: newdata
!ポインタ root%next は最初のデータを指すallocate(root, root%next)nullify(root%next%next)
!リストを作るwork => root%nextwrite(*,*)’数値 (integer)を read,非負値ならばリストに追加,負値ならば exit’do while(.true.)
read(*,*) newdataif(newdata >= 0) then
work%dat=newdataallocate(work%next)work=>work%nextnullify(work%next)
elsewrite(*,*)’ 負値なので exit’exit
end ifend do
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 18/25
木村拓馬
.f90(例).. Link
作業ポインタをリストの最初と結合.作業ポインタのデータ部をwrite し,作業ポインタをnext と結合.
allocateしたら deallocateしないと警告が出る.
.リスト構造を作る例(ex12.1.f90)後半..
......
!リストを表示write(*,*)’ リストを表示’work => root%nextdo while(associated(work%next))
write(*,fmt=’(i5,",")’,advance=’no’) work%datwork=>work%next
end dowrite(*,*)
!リストを解放work => rootdo while(associated(work%next))
root => workwork=>work%nextdeallocate(root)
end dodeallocate(work)
end program pointer_list
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 19/25
木村拓馬
.例:削除と挿入 (ex12.2.f90 の一部) .. Download
..
......
!リストを挿入work => rootwrite(*,*) ’ リストを挿入\n 何番目に挿入?(’,1,’-’,n,’)-->’read(*,*) mallocate(temp)do i=1,m-1
work=>work%nextend dotemp%next=>work%nextwork%next=>tempwrite(*,*) ’ データ(integer)を入力-->’read(*,*) temp%datn=n+1
⇒ ⇒
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 20/25
木村拓馬
.例:削除と挿入 (ex12.2.f90 の一部) .. Download
..
......
!リストを削除work => rootwrite(*,*) ’ リストを削除’write(*,*) ’ 何番目を削除?(’,1,’-’,n,’)-->’read(*,*) mdo i=1,m-1
work=>work%nextend dotemp=>work%nextwork%next=>work%next%nextdeallocate(temp)n=n-1
⇓
⇓
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 21/25
木村拓馬
.演習 12.1(pr12.1.f90)..
......
p.18-21の例を書き換えて,入力したデータを値の大きい順に並べ替えるプログラムを作成しよう.
入力するデータは,通し番号(3文字の文字列)と整数値が n組.
出力は,並べ替えられた通し番号と整数値.
構造体とポインタを利用すること(自己参照構造体によるリスト構造)..データの例..
......
d01, 41
d02, 6
d03, 42
d04, 94
d05, 20
.出力の例..
......
ID, VALUE
d04, 94
d03, 42
d01, 41
d05, 20
d02, 6
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 22/25
木村拓馬
参考文献
[1] JIS X 3001-1:2009 (プログラム言語 Fortran –第 1部:基底言語)∣∣∣∣ 附属書 C に,「“再帰的”な型の定義」(自己参照構造体),線形リストの例が少しだけ掲載されています.
[2] 戸川隼人: 「ザ・Fortran90/95」,サイエンス社 (1999)
[3] Les Hancock, Morris Krieger, Saba Zamir (倉骨彰,三浦明美訳): C言語入門THE C Primer,アスキー出版局(1984)∣∣∣∣ FORTRANで自己参照構造体・リスト構造を扱っている書籍が手元に無かったので,
C 言語の入門書にある内容を移植しました.
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 23/25
木村拓馬
Appendix
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 24/25
木村拓馬
.演習 11.2(pr11.2.f90)..
......
売上表を出力するプログラムを以下の仕様に従って作成してみよう.
売上データは店舗 ID(101からの通し番号とする),店舗名(20文字),売上金額の三項目とし,構造体を用いること.
売上データはファイルから読み込むようにすること.なお,ファイルの 1行目には総店舗数が書かれているものとする.
出力は「店舗 ID順」,「売上金額の多い順」の 2種類の並び替えを画面に表示すること.
今回は副プログラムやモジュールを使用しないこと..pr11.2data.txt..
......
3
101 aaa 1000
102 bbb 2000
103 ccc 3000
.出力の例..
......
ID
| 101 | aaa | 1000 |
| 102 | bbb | 2000 |
| 103 | ccc | 3000 |
KINGAKU
| 103 | ccc | 3000 |
| 102 | bbb | 2000 |
| 101 | aaa | 1000 |
.選択ソート..
......
1) データ x1, x2, · · · , xn の中での最大値を探し,x1 と入れ替える.
2) データ x2, x3, · · · , xn の中での最大値を探し,x2 と入れ替える...n) データ xn−1, xn の大きい方を xn−1 と入れ替える.
FORTRAN プログラミング,–第 11・12 回 ポインタとリスト構造– ( 2014年12月16日 21:43 ) 25/25