自作関数の作成とそれを利用した計算 


  自作関数(関数の定義)
  
 複雑な計算プログラムを作成していると自分が定義した関数を使いたいことがある。
 下の例は、2点間の距離を求める関数(dist)を組み入れて、3角形の周囲長さを計算するプログラムである。
(実際に3角形となるかどうかのチェックは組み入れていない。) 
なお、関数名は例のように予め定められた名前(mainなど)を除いて、変数名と同様に自由につけることができる。

 この例題プログラムを実行したら、3組の座標(x,y)を入力してみよう。例えば、
1.0 2.0  [Enter]
2.0 4.0   [Enter]
3.5 2.5  [Enter]
である。
 この入力後に、3辺の長さの合計が表示される。
また、検算用にいわゆる”3、4、5”の三角形を入力してみよう。
1.0 2.0  [Enter]
4.0 2.0  [Enter]
4.0 6.0  [Enter]
結果、12.0が表示される。

この例題のパターンを利用して自分で関数を定義できるように訓練しよう。

 なお、8行目の変数d(のような変数)をローカル変数といい、この変数は関数distの中でしか用いることができない。
逆に17行目のds(これもメイン関数[main]内でしか用いることができない)を関数dist内で用いることはできない。
 また、6行目のx1〜y2までを関数distの引数(ひきすう)といい、27行目の例でもわかるように、関数を
呼び出す側の変数と名前が異なっていても(逆に25行目のように同じでも)よい。

 ※ ローカル(局所的)変数に対してグローバル(大域的)変数という変数も存在するが、
   本授業では、いまのところ使用しない。

 

 ● 自作関数(関数の定義)
001:
002:
003:
004:
005:
006:
007:
008:
009:
010:
011:
012:
013:
014:
015:
016:
017:
018:
019:
020:
021:
022:
023:
024:
025:
026:
027:
028:
029:
030:
031:
/*  func02.c  */
 
#include <stdio.h>
#include <math.h>
 
double dist(double x1,double y1,double x2,double y2)
{
    double d;
    d=sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
    return d;
}
 
int main(void)
{
    int i;
    double x1,x2,x3,y1,y2,y3;
    double ds;
    printf("No.1 [x,y] : ");
    scanf("%lf %lf",&x1,&y1);
    printf("No.2 [x,y] : ");
    scanf("%lf %lf",&x2,&y2);
    printf("No.3 [x,y] : ");
    scanf("%lf %lf",&x3,&y3);
    ds=0;
    ds=ds+dist(x1,y1,x2,y2);
    ds=ds+dist(x2,y2,x3,y3);
    ds=ds+dist(x3,y3,x1,y1);
    printf("nagasa=%f\n",ds);
 
    return 0;
}
001:
002:
003:
004:
005:
006:
007:
008:
009:
010:
011:
012:
013:
014:
015:
016:
017:
018:
019:
020:
021:
022:
023:
024:
025:
026:
027:
028:
029:
030:
031:
-
-
-
数学関数の使用にはこの文が必要 
-
自作関数 distの定義 
-
関数内での変数dの宣言 
2点間の距離を計算 
関数の戻り値としてdを指定 
-
-
-
-
-
-
-
-
-
-
-
-
-
dsを初期化 
dsに各頂点間の距離を足していく 
-
-
dsの表示 
-
-
-

 

 

 [問題11] 円錐の体積は (1/3)πrh で表せる(r:半径、h:高さ)。円錐の体積を計算する関数を作り、その関数をメイン関数から呼び出して、計算結果を表示するプログラムを作りなさい。ただし、関数の引数は、r と h とし、円周率πは3.141593 とする。なお、下に一部未完成のプログラム例を記載した。未完成部分は各自が考えてほしい。 


001:
002:
003:
004:
005:
006:
007:
008:
009:
010:
011:
012:
013:
014:
015:
016:
017:
018:
019:
020:
021:
022:
023:
024:
/*   pra11.c               */ 
  
#include <stdio.h> 
#include <math.h> 
  
double volensui(double r, double h) 
    double pi; 
    double v; 
    pi=3.141593; 
    /* v=????? */ 
    return v; 
  
int main(void) 
    double hankei,takasa; 
    double taiseki; 
    /*     input */ 
    /*    call func. */ 
    printf("taiseki=%f\n",taiseki); 
 
    return 0; 
001:
002:
003:
004:
005:
006:
007:
008:
009:
010:
011:
012:
013:
014:
015:
016:
017:
018:
019:
020:
021:
022:
023:
024:
関数 volensui の定義 
    (引数はrとh)  
   変数piの宣言   
   変数vの宣言 
   piに円周率の値を設定 
   体積vの計算 
   関数の戻り値としてvを指定 
  変数の定義    
  変数の定義 
  半径と高さの入力 
  関数の呼び出 
  結果の表示 
-
-

 


  再帰処理
        関数が自分自身を呼び出す処理を行うことである。再帰呼び出しともいう。
    数列処理などに用いるとプログラムを簡潔に記述することができる。
         また、子・孫フォルダを含むフォルダ内全ファイルのリストアップ処理にも利用される。
     ただし、専門的に解説すると、ローカル変数領域(スタックと呼ばれる)をどのくらい消費するのか
    実行前には不明である点、無限ループに陥る可能性がある点、実行速度の低下など欠点も存在する。
    以下に再起処理の典型的な例である階乗の計算を示す。


 ●  再帰処理を用いた階乗の計算
001:
002:
003:
004:
005:
006:
007:
008:
009:
010:
011:
012:
013:
014:
015:
016:
017:
018:
019:
020:
021:
022:
023:
/*  factrec.c  */
 
#include <stdio.h>
 
int fact(int n)
{
    if (n <= 1) return 1;
    return fact(n - 1) * n;
}
 
int main(void)
{
 
    int n,f;
 
    n=10;
 
    f=fact(n);
 
    printf("%d! = %d\n",n,f);
 
    return 0;
}
001:
002:
003:
004:
005:
006:
007:
008:
009:
010:
011:
012:
013:
014:
015:
016:
017:
018:
019:
020:
021:
022:
023:
-
-
-
-
階乗の自作関数(再帰呼出使用)
-
nが1になると1を返して脱出する
ここが再帰呼び出し
-
-
-
-
-
-
-
nはあまり大きくできない
-
ここで関数factを呼び出す
-
結果の表示
-
-
-

  簡単な解説

  関数は通常次の文(命令)に戻ってくる。
  例えば、
  a=fa(x); c=a;
  b=fb(y); d=b;
  の場合、a=fa(x)が終了したら c=a が実行される。
  これをあてはめると
  fact(5)は次のイメージになる

  fact(5) 
       -> (fact(4)*5)
         -> ((fact(3)*4)* 5)
                        -> (((fact(2)*3)*4)* 5)
                                     ->((((fact(1)*2)*3)*4)* 5)
                     ->((((1*2)*3)*4)* 5)

    ここまでは関数戻り先の登録が行われるのみで関数後の計算は実行されない
  (青色の部分)
  fact(1)=1で再帰呼び出しが終了すると登録とは逆順に計算が実行されていく。
  すなわち括弧の内側からである。
  fact(5)  =   ((((1 *2)*3)*4)* 5)
  よって階乗が正しく計算できる。

     これをより理解しやすくしたものがこのプログラム である。
  関数内の画面表示によって実行手順が把握できる。

 戻る