2 関数とは何か

2.1 main()関数と関数の構造

1年生の時に学習したFORTRANを覚えている人は,サブルーチンを思い出して欲しい.それ が,C言語の関数に相当する.いかなるプログラミング言語でも,このサブルーチンに相 当する機能がある.それだけ便利な機能であるということである.

これまでの学習で,諸君は知らない間に関数を使っていた.おまじないと言っていたもの の一部はmain()関数と呼ばれるものである.いままでのプログラムを思い出してほ しい.必ず,mainとか言うものを書いていたはずである.

main()関数にかぎらず,これから学習する関数は同じような構造である. main()関数の構造を図1に示す.それぞれの役割は,以下の とおりである.

このmain()関数の例でも分かるように,関数での処理の内容はブロック--中括弧 { }で囲まれた部分--中に書かれなくてはならない.今まで,学習してきたプロ グラムでは,main関数のみがあり,その中に実行文が書かれていたはずである.プ ログラムでは,このブロックを処理のひとかたまりと考える.

main関数は特別で,C言語のプログラムには,必ず1個必要で,そこから実行される ことになっている.

図 1: main()関数の構造
\includegraphics[keepaspectratio, scale=1.0]{figure/main_function.eps}

2.2 関数の例

実際のC言語のプログラムは,main関数のみからできていることは希で,リスト 1のように複数の関数からできている.C言語のプログラムは関数の集合 から構成され,それらが順番に呼び出されて処理を行う.リスト1を例 に関数の動作を考えよう.

このプログラムでは,main関数とbiggerと言う関数が使われている. main関数の構造については,先ほど述べたとおりである.biggerの方は,次の ようになっている.

このリスト1の動作の内容を,図2のフローチャー トに示す.動作は単純なので,すぐに理解できるであろう.関数を使って,大きい方の値 を調べ,表示している.

数学の関数とほとんど同じような動作をしていることが分かるだろう.数学では変数を与 えて,関数値が求まる.C言語では,変数に代わり引数が与えられ,戻り値がも求まるわ けである.

   1 #include <stdio.h>
   2 
   3 double bigger(double a, double b);   /* プロトタイプ宣言 */
   4 
   5 /*=====================================================================*/
   6 /*    メイン関数                                                      */
   7 /*=====================================================================*/
   8 int main(void){
   9   double x, y, z;
  10 
  11   x=2.5;
  12   y=3.1415;
  13 
  14   z=bigger(x, y);
  15 
  16   printf("大きい方は、%fです。\n", z);
  17 
  18   return 0;
  19 }
  20 
  21 /*=====================================================================*/
  22 /*    大きい方を探す関数                                               */
  23 /*=====================================================================*/
  24 double bigger(double a, double b){
  25   double big;
  26 
  27   if(a<b){
  28     big = b;
  29   }else{
  30     big = a;
  31   }
  32  
  33   return big;
  34 
  35 }
図 2: リスト1の動作フローチャート
\includegraphics[keepaspectratio, scale=1.0]{figure/function_call.eps}

2.3 関数の役割

関数は,長いプログラムを効率よく記述するために必要である.そのために,この関数には2つの役 割がある.一つは,同じような処理を一つにまとめることである.実際のプログラムの動 作は,同じ処理,あるいは似たような処理が非常に多い.いちいちそれを書くとプログラ ムが長くなり,プログラマーは大変である.そこで,一つにまとめ,必要なときに呼び出 すのである.

もう一つ,長いプログラムの問題は,処理が分かりにくい点である.例えば, windows2000だとソースプログラムは大体4000万行だと言われている.この場合,それぞ れの実行文の役割など分からない.コンピューターは大量のトランジスターからできてい るが,それぞれの役割が分からないのと同じである.このように大量の部品(実行文)から 構成されるコンピューター(プログラム)の動作を考える際に重要なことは,モジュール 3に 分解することである.そうすると,動作の内容が分かるようになる.長いプログラムを作 る場合も同じで,機能単位(モジュール)に分け,分かりやすくすることが重要である.C 言語では関数を使い,機能単位にプログラムを分割する.

まとめると,関数の役割は

である.特に,2番目が重要で,「プログラムのソースは分かりやすくなくてはならない」 ということを,肝に銘じておかなくてはならない.

2.3.1 同じ処理をまとめる

関数の役割の一つの「同じ処理をまとめる」ことの例を示す.そのために,大きさ10の配 列a[]と大きさ100の配列b[]に整数の乱数を格納し,その最値を求めるプログ ラムを考える.リスト2のようなプログラムである.

このプログラムでは,乱数を使っている.乱数の発生方法については,このプリントの付 録([*]以降)に書いてある.又教科書のp.449のsrand関数の説明の 部分にも書いてある.

   1 #include <stdio.h>
   2 #include <stdlib.h>
   3 #include <time.h>
   4 
   5 int main(void){
   6   int a[10], b[100], max_a, max_b, i;
   7 
   8   srand((unsigned int)time(NULL));          /* 起動毎に異なる乱数発生のため */
   9 
  10   for(i=0; i<10;   i++) a[i]=rand();     /* 配列 a[] の値設定 */
  11   for(i=0; i<100;  i++) b[i]=rand();     /* 配列 b[] の値設定 */
  12 
  13   /* ---- 配列 a[] の最大値検索 ----- */
  14   max_a=a[0];
  15   for(i=1; i<10; i++){
  16     if(max_a<a[i]) max_a=a[i];
  17   }
  18 
  19   /* ---- 配列 b[] の最大値検索 ----- */
  20   max_b=b[0];
  21   for(i=1; i<100; i++){
  22     if(max_b<b[i]) max_b=b[i];
  23   }
  24 
  25   printf("max a=%d\n",max_a);             /* 最大値印刷 */
  26   printf("max b=%d\n",max_b);
  27 
  28   return 0;
  29 }

リスト2をよく見ると,最大値を求める部分はほとんど同じ である.そこで,それを一つの関数にまとめることを考える.リスト 3のようにすれば良い.これで,プログラムがすっきりした.こうす ると,最大値を求めるアルゴリズムを変えたい場合でもプログラムの変更が容易である.

   1 #include <stdio.h>
   2 #include <stdlib.h>
   3 #include <time.h>
   4 
   5 int find_max(int n, int ix[]);            /* プロトタイプ宣言 */
   6 
   7 /*=========================================================================*/
   8 /*    main 関数                                                            */
   9 /*=========================================================================*/
  10 int main(void){
  11   int a[10], b[100], max_a, max_b, i;
  12 
  13   srand((unsigned int)time(NULL));          /* 起動毎に異なる乱数発生のため */
  14 
  15   for(i=0; i<10;   i++) a[i]=rand();     /* 配列 a[] の値設定 */
  16   for(i=0; i<100;  i++) b[i]=rand();     /* 配列 b[] の値設定 */
  17 
  18   max_a=find_max(10, a);
  19   max_b=find_max(100,b);
  20 
  21   printf("max a=%d\n",max_a);             /* 最大値印刷 */
  22   printf("max b=%d\n",max_b);
  23 
  24   return 0;
  25 }
  26 
  27 /*=========================================================================*/
  28 /*    最大値探索の関数                                                       */
  29 /*=========================================================================*/
  30 int find_max(int n, int ix[]){
  31   int i, max;
  32 
  33   /* ---- 配列 a[] の最大値検索 ----- */
  34   max=ix[0];
  35   for(i=1; i<n; i++){
  36     if(max<ix[i]) max=ix[i];
  37   }
  38   
  39   return max;
  40 }

2.3.2 処理をまとめてプログラムを分かりやすく

関数のもう一つの機能「処理をまとめてプログラムを分かりやすく」の例である.リスト 2のメイン関数の部分の処理を分かり易くするために,関数 を用いた例をリスト4に示す.
   1 #include <stdio.h>
   2 #include <stdlib.h>
   3 #include <time.h>
   4 
   5 /* ----  プロトタイプ宣言 -----  */
   6 void make_data(int nx, int ix[], int ny, int iy[]);
   7 int find_max(int n, int ix[]);            
   8 void print_results(int a, int b);
   9 
  10 /*=========================================================================*/
  11 /*    main 関数                                                            */
  12 /*=========================================================================*/
  13 int main(void){
  14   int a[10], b[100], max_a, max_b;
  15 
  16 
  17   make_data(10, a, 100, b);                /* 乱数データ作成 */
  18 
  19   max_a=find_max(10, a);                   /* 最大値検索 */
  20   max_b=find_max(100,b);
  21 
  22   print_results(max_a, max_b);             /* 最大値印刷 */
  23 
  24   return 0;
  25 }
  26 
  27 
  28 /*=========================================================================*/
  29 /*    データ作成                                                            */
  30 /*=========================================================================*/
  31 void make_data(int nx, int ix[], int ny, int iy[]){
  32   int i;
  33 
  34   srand((unsigned int)time(NULL));          /* 起動毎に異なる乱数発生のため */
  35 
  36   for(i=0; i<nx; i++) ix[i]=rand();
  37   for(i=0; i<ny; i++) iy[i]=rand(); 
  38   
  39 }
  40 
  41 
  42 /*=========================================================================*/
  43 /*    最大値探索の関数                                                       */
  44 /*=========================================================================*/
  45 int find_max(int n, int ix[]){
  46   int i, max;
  47 
  48   /* ---- 配列 a[] の最大値検索 ----- */
  49   max=ix[0];
  50   for(i=1; i<n; i++){
  51     if(max<ix[i]) max=ix[i];
  52   }
  53   
  54   return max;
  55 }
  56 
  57 
  58 /*=========================================================================*/
  59 /*    結果の印刷                                                             */
  60 /*=========================================================================*/
  61 void print_results(int a, int b){
  62 
  63   printf("max a=%d\n",a);
  64   printf("max b=%d\n",b);
  65   
  66 }

ホームページ: Yamamoto's laboratory
著者: 山本昌志
Yamamoto Masashi
平成19年5月30日


no counter