関数と手続き


  1. 関数とは
    #include <math.h>
    .....
    y = sin (1.5); ← 関数(ライブラリ関数)
    .....
    


    C言語:「プログラムとは関数の集まりである」→「利用者は関数を作成する必要がある」


  2. 関数を利用するメリット
  3. 関数定義
    関数値のデータ型名 関数名(引数1のデータ型 引数1, ..., 引数nのデータ型 引数n)
    	{
    		関数内で用いるデータの宣言部分
    		関数の本体
    		リターン文(戻り値)
    	}
    


  4. 実際の関数例
  5. 関数の呼出
    add(int x, int y)
    {
    	return (x +y);
    }
    
    main()
    {
    	int a, b, c;
    	a = 1; b = 2;
    	c = add(a, b);
    	printf("%d¥n", c);
    
    	printf("5 +3 = %d¥n", add(5, 3));
    }
    


  6. ローカル変数とグローバル変数(変数の有効範囲; scope)
  7. 関数を作成する際の注意点

  8. 練習問題1:結晶によるX線回折において、実際の回折強度にはこれまでに計算してきたF2に加えて、 回折角度に依存するローレンツ因子Lを考慮する必要がある。そのLは次式で与えられ、

    L = (1+cos22θ)/(sin2θcosθ)


    X線回折強度 I は、

    I  ∝ L × F2


    である。前回作成したプログラムに、このローレンツ因子を計算する関数を加え、 X線回折強度が0.001以上の面を表示を得るプログラムに改良せよ。以下に計算結果を示す。

    (実行例:入力部分は下線部分)
    
    Lattice constant a, c (nm) = 0.3209 0.5211
    Wavelength (nm) = 0.15405
    Number of atoms in unit cell = 2
    No. 0 (x, y, z, f) = 0 0 0 12
    No. 1 (x, y, z, f) = 0.6667 0.3333 0.5 12
    
    
  9. 再帰的関数呼び出し(recursive call)

    →関数の中でその関数自身を呼び出すこと

    リスト8.2(p.62)を簡略化したこのプログラムを入力し、その動作について考えてみよ。



    再帰的関数呼び出しを利用する際の注意事項
    • 漸化式等をプログラムするのに非常に有用
    • 実行速度の低下や記憶容量の増加を伴うので、上の有用さとのバランスを考慮
    • 無限ループに注意


  10. 練習問題2:p.70の課題4に取り組んでみよ。解答例(fractorial2.c

  11. 手続き(Procedure)
    • 関数と同様な定義、利用方法
    • ただし、幾つもの変数を処理し、その結果を返すことが可能

  12. 手続きの例
    void calc(int a, int b, int *x, int *y)
    {
    	*x = a + b;
    	*y = a - b;
    }
    main()
    {
    int a, b, x, y;
    	a = 1; b =2;
    	calc(a, b, &x, &y);
    	printf("%d %d¥n", x, y);
    }
    


  13. 上の例の解説
    • main中からcalcを呼ぶときにa, bは従来と同様
      →a, bの中身(この場合1と2)をcalcに引き渡す。(値呼び;call by value)
    • しかし、x, yの前には&がついている。
      →x, yの「変数のアドレス(変数がメモリ上において格納されている番地)」を手続きcalcに引き渡す。(参照呼び;call by reference)
    • この場合、x, yのアドレスが手続きcalcに引き渡されるので、それを受けるcalcでのx, yの変数宣言はポインタ型。
    • 関数calcの中で、x, yの値を参照するには、*x, *yを用いる。

  14. 配列を手続きおよび関数に引き渡す方法
    • 配列名(例えばa[100]のa)は一連の配列が格納されているメモリ領域の先頭アドレスを有している。
      →「配列名」はポインタ変数。詳しくは、配列とポインタ(第6回)を参照のこと。
      例1)
      #include <stdio.h>
      
      void reverse(int *a) /* int a[], int a[10]も可 */
      {
      int b[10],i;
      for(i=0; i<10; ++i) b[9-i] = a[i];
      for(i=0; i<10; ++i) a[i] = b[i];
      }
      
      main()
      {
      int a[10]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, i;
      reverse(a);
      for(i=0; i<10; ++i) printf("%d\n", a[i]);
      }