◎第10回 手続き


下へ一覧へ ○テキスト 5章(5.1)
下へ上へ 手続き:段階的詳細化をプログラミング言語上で記述する機構 ○「手続き」とは何か procedure=プロシージャ ある一連の操作を、分離して、記述したもの。 ○「手続き」を使う利点 ・区切りのいいところをまとめて、別に記述する。 プログラムが見やすくなる。(段階的詳細化向き) ・大きな(複雑な)処理を分割してデバッグなどを しやすくする。→ モジュール化 ・似かよった操作がしばしば行なわれるとき 同じプログラムを何度も書かないですむ。
下へ上へ ○手続きの定義と呼出 手続きの「まとまった処理の内容」を記述する部分 手続きの「定義」 その手続きを使う部分 「手続き呼出」 ○手続きの種類 関数 : 結果として「値」を返す。一般に「副作用」がない方がよい。 ( 副作用:値を返す意外に状態に及ぼす影響 ) function 返す値の「型」に注意が必要。 サブルーチン : 「値」を返さない。「作用」がある。 subroutine C では、まとめて「関数」と呼ぶ。 ( 「function」には、「機能」の意味があるので、英語では 違和感はないも知れない ) メインルーチン : サブルーチンに対してプログラムを起動した時 最初に実行される手続き main routine 下へ上へ C言語では、main という 「関数」が最初に実行される。 C言語であらかじめ用意されている関数の例 sqrt( ) , sin( ) , cos( ) C言語であらかじめ用意されている「サブルーチン的関数」の例 printf( ) , scanf( )
下へ上へ ○自分で「関数」を定義する方法 実はすでに main という名の関数を定義している。 適当な名前をつければよい。 あらかじめ用意されている関数と同じ名前は使えない。 (使える場合もある) 関数の定義と使用の方法 まず例を示す。 例1: 二つの double 型のデータを受け取って その 2 乗の和の平方根を返す関数とその呼出
下へ上へ #include <stdio.h> #include <math.h> double kansuu( x, y ) double x, y; { double z; z=sqrt( x*x+y*y ); return z; } /* 下へ上へ */ main() { double a, b, c; a=1.0; b=2.0; printf("a=%g , b=%g\n",a, b ); c=kansuu( a, b ); printf("c=%g\n",c); /* 「printf」 も関数であるが、このように関数呼出の実パラメタとして 用いてもよい。*/ printf("関数 kansuu( 3, 4 )=%g\n", kansuu( 3.0, 4.0 ) ); exit(0); }
下へ上へ ◎関数の定義 関数の返す値の型 関数名( 仮パラメタ名リスト ) 仮パラメタ名の型宣言 ブロック ◎関数の呼出 式の中で 関数名(実パラメタリスト) の形で使えばよい。
下へ上へ ◎パラメタ 手順は同じだが「対象は異なる」 関数内での操作記述のための仮の名前 仮パラメタ、仮引数(かりひきすう)、formal parameter kansuu の x や y 関数を呼び出すときに指定する実際の操作対象 実パラメタ、実引数(じつひきすう)、real parameter main の kansuu( a, b ) の a や b ◎変数の扱い 局所変数 : ある関数内のみで使われる変数 local 変数 上の例 kansuu の中の z 上の例 main の中の a, b, c 大域変数 : すべての関数で使うことのできる global 変数 これまで出て来た変数はすべて local 変数 local 変数は名前は同じでも関数が異なると 別のものとして扱われる。 ( global 変数は、「関数の外」で宣言する。 「関数」と同じ名前は使えない。) ( Pascal では、local 関数 もある。)
下へ上へ ◎パラメタの対応方法 (値パラメタ,変数パラメタ) 値渡し : 変数(式)の値を渡す 関数で仮パラメタを変更しても (コピーを渡す) 呼び出し側の実パラメタは変わらない 変数渡し : 変数のアドレスを渡す 関数で仮パラメタを変更すると 呼び出し側の仮パラメタも変わる 言語による違い 変数渡し Fotran 値渡し C (Pascal は指定可能) C の仮パラメタは、ほとんど「局所変数」であり、 呼出時に実パラメタの値が自動的に代入される と考えられる。 (関数の詳細)
下へ上へ C で値を返すとき 1. 「関数」なので関数の値として返す。 一つだけ 2. パラメタとして変数のアドレスを渡す。 いくつでも可 2.の説明 「アドレスを渡す」 実パラメタに「& 変数」を書く 対応する仮パラメタは変数名の先頭に * をつける。 ( これはかけ算の意味ではない。ポインタ変数 ) ( 仮パラメタの名前の()無いのリストにはつけない。 仮パラメタの宣言と実際に使用する部分でつける) 配列を渡す = 先頭要素のアドレスを渡す。 ( 場所が連続しているので、先頭のアドレスと1要素の大きさを 知ればよい。)
下へ上へ 例2 #include <stdio.h> /* 総和の計算の関数 */ double souwa( a, n ) double *a; int n; { int i; double s; s=0; i=0; while( i<n ){ s=s+a[i]; i=i+1; } return s; } /* 下へ上へ */ #define N 100 main(){ int i, n; double x[N], s; /* データの代入 */ x[0]=1.0; x[1]=4.0; x[2]=-3.0; x[3]=9.0; x[4]=8.0; n=5; /* データの表示 */ /* これも関数として別に記述すると 便利であろう */ i=0; while( i<n ){ printf("x[%d]=%g\n",i, x[i] ); i=i+1; } /* 総和の計算の本体 */ s=souwa( x, n ); /* 結果の表示 */ printf("総和は %g です。\n", s ); exit(0); }
下へ上へ 例3 2整数の和と差を計算して返す関数(サブルーチン) #include <stdio.h> watosa( x1, x2, wa, sa ) int x1, x2, *wa, *sa; { *wa = x1+x2; *sa = x1-x2; return; } /* 下へ上へ */ main() { int a, b; int sum, diff; a=10 ; b=8 ; printf("a=%d b=%d\n", a, b ); watosa( a, b, &sum, &diff ); printf("wa=%d sa=%d\n", sum, diff ); watosa( 25, 30, &sum, &diff ); printf("wa=%d sa=%d\n", sum, diff ); exit(1); }
下へ上へ 仮パラメタの宣言 値パラメタ 型 仮パラメタ名; 宣言例 int a; 使い方 a 配列変数パラメタ 型 *仮パラメタ名; 宣言例 int a[]; (または、 int *a ) 使い方 a[i] 変数パラメタ 型 *仮パラメタ名; 宣言例 int *a; 使い方 *a
下へ上へ ◎ C の関数の宣言の補足 1. C の関数の宣言の方法には、上で示した以外に、処理内容を 示さずに、返す値だけを宣言する方法がある。 例 double kansuu(); もちろんこれは、「他のところ」で処理内容を示したものが なくてはならない。 ( #include で示したファイルには、あらかじめ用意された 関数の型宣言が含まれている。) 2. C では、新たな規格にもとづいた、関数の仮パラメタ宣言方法がある。 これは、通常のコンパイラ cc の代わり別のコンパイラ gcc を使う ことで、利用できる。 従来方式 traditional double kansuu( x, y ) double x, y; { .... 比較的新しい方式 ( ANSI 方式 ) double kansuu( double x, double y ) { ... こうすると、呼び出すときにパラメタを与える方法がわかる。 ANSI 方式の関数型だけの宣言は double kansuu( double x, double y ); である。この x は y はなくてもよい。
下へ上へ ○演習 1. 次のプログラムで、 #include をなくした時の動作を調べよ。 #include <math.h> main() { double x; scanf("%lf", &x ); printf("exp(%f)=%f\n", x, exp(x)); } 2. 次の c プログラムの指定した各処理や条件判断が実行される順番を考えよ。 また、このプログラムは、 % ~eenagai/ic2/c-order ファイル名 で実行した部分が表示されるので確認せよ。 ~eenagai/ic2/c-order4.c
3. 第4回の数値積分プログラム(~eenagai/ic2/integral.c)を 処理部分を書き直し積分値を値として返す関数として 全体を書き直しコンパイル・実行して動作を確認せよ。 ( 解答例(~eenagai/ic2/integral-f.c) ) 一覧へ上へ ○レポート課題(解答) 1. 第5回の整列プログラムにおいて、整列部分,データ入力, データ出力を関数として書き直し、コンパイル・実行して動作を確認せよ。 (今回の総和の例が参考になるであろう) (ヒント:~eenagai/ic2/seiretu10.c) 2. 第5回の2分法のプログラムにおいて、 処理部分を解を値として返す関数として 全体を書き直し、コンパイル・実行して動作を確認せよ。 (今回の総和の例や演習3の解答例が参考になるであろう)
一覧へ