2 関数(サブルーチン)

2.1 単語の意味

ここでは、C言語の関数について、学習する。関数と言うよりも、サブルーチンと言った 方が実際の動作が理解しやすい。C言語では関数と呼ばれるが、サブルーチンと言う言葉 もコンピューター科学の世界では、よく使われるので、ほとんど同義語として理解して欲しい。 C言語の文法を学習する前に、これがどのようなもので、なぜ便利なのか説明し ておくことが重要であろう。これが分かれば、関数が分かったも同然である。どんなプロ グラミング言語でもその文法を理解するよりも、それが必要な理由を理解する方がずっと 重要であることを忘れないで欲しい。関数(サブルーチン)は非常に便利なので、ほとんど のプログラム言語でも実装されている。ここでその内容を理解し、将来、他の言語を学 ぶときに応用できるようになるこを望む。

少し聞き慣れない単語が出てきたので説明しておく。これらは全て、英語である。関数も、 元は function を日本語に直した。元の英語の意味を知っておくことは、その機能の理解 に役立つ。それらの意味は、以下の通りである。

routine(ルーチン)
1.決まってすること、日課。2. いつもの手順、所定の手順。 3.(コンピューター)ルーチン$ \le$プログラム中の所定の機能をはたすひとまとまりの部分$ \gt$
main(メイン)
主な、主要な、中心となる
sub(サブ)
function(ファンクション)
1.機能、働き、作用。2. 関数

通常のプログラムは、サブルーチンとメインルー チンから構成される。諸君が今まで作成してきたプログラムの最初の方にint main()と書いてきたはずである。それがメイン関数であり、メインルーチンと呼ばれる 者である。その範囲は、括弧{から}までである。知らないうちに、メイン関数を 使ってきているのである。これ以外の関数の作り方を学習する。

2.2 どちらのプログラムが分かりやすいか

関数(サブルーチン)を使うことのメリットは、なんと言ってもソースコードが分かりやす いと言うことである。ソースコードが分かりやすいので、それを記述するのも簡単といえ る。実際に比べてみよう。入力された整数が素数か否か判定するプログラムを例にする。 プログラムの動作は、次の通りである。

2.2.1 関数(サブルーチン)を使わない場合

#include <stdio.h>

/*==============================================================*/
/*   main function                                              */
/*==============================================================*/
int main(void){
  int i, test, amari;
  char temp;

  /* ---------- キーボードからデータ入力 ------------------*/

  do{
    printf("\n調べたい整数を入力してください(2以上)\n");
    scanf("%d%c",&test,&temp);
    printf("素数の判定をする整数は、%dです。\n",test);
  }while(test<2);

  /* ---------- 素数判定(割り切れる最小) -----------------*/

  amari = 0;

  i=1;
  do{
    i++;                      /* iのインクリメント(1増加) */
    amari = test % i;         /* test/i の余りの計算   */
  }while(amari != 0 && i <= test);


  /* ---------- 結果表示 --------------------------------*/

  if(test == i){
    printf("\n%dは素数です !!\n\n",test);
  }else{
    printf("\n%dは素数ではありません !!\n",test);
    printf("割り切れる最小の整数(>2)は、%dです。\n\n",i);
  }

  return 0;
}

2.2.2 関数(サブルーチン)を使う場合

#include <stdio.h>

int key_in(void);
int check_prime(int number);
int print_result(int number, int result);

/*==============================================================*/
/*   main function                                              */
/*==============================================================*/
int main(void){
  int test, kekka;

  test   = key_in();           /* キーボードからデータ入力  */
  kekka = check_prime(test);   /* 判定(割り切れる最小)     */
  print_result(test,kekka);    /* 結果表示                */

  return 0;
}


/* <<<<<<<<<< これ以降は、サブルーチン >>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

/*==============================================================*/
/*   キーボードから整数を読み込む関数                                */
/*==============================================================*/
int key_in(void){
  int n;
  char temp;

  do{
    printf("\n調べたい整数を入力してください(2以上)\n");
    scanf("%d%c",&n,&temp);
    printf("素数の判定をする整数は、%dです。\n",n);
  }while(n<2);

  return n;
}


/*==============================================================*/
/*   素数の判定                                                  */
/*==============================================================*/
int check_prime(int number){
  int i,amari;
  
  amari = 0;

  i=1;
  do{
    i++;                      /* iのインクリメント(1増加) */
    amari = number % i;       /* number/i の余りの計算   */
  }while(amari != 0 && i <= number);

  return i;
}


/*==============================================================*/
/*   結果の表示                                                  */
/*==============================================================*/
int print_result(int number, int result){

  if(number == result){
    printf("\n%dは素数です !!\n\n",number);
  }else{
    printf("\n%dは素数ではありません !!\n",number);
    printf("割り切れる最小の整数(>2)は、%dです。\n\n",result);
  }

  return 0;
}

2.3 大規模プログラムの構造(自動車を例にして)

コンピューターのプログラムは、皆さんが練習問題で作成する数行のものから、 Windows2000の4千万行に及 ぶものまで多種多様である。このような長いプログラムを書く場合、サブルーチンという 考え方がないと、不可能である。

長いプログラムの書き方の説明に入る前に、アナロジー(analogy 類似)として、自動車を 作ることを考がえる。自動車も製品で、プログラマーにとってプログラムがそれに当たる。 自動車は、非常に多くの部品から出来上がっている。たとえば、ピストン、シリンダー、 ボルト、プラグ、タイヤ、ハンドル、ばね、電線、電球、集積回路、コンデンサー、火薬、 磁石$ \cdots$など、それこそ大変な数の部品から作られている。そして、これを組み合わ せて自動車が出来上がる。これを、一人で設計することは到底不可能なことは想像できる。 それでは、どうやって設計するかと言うと、多くのエンジニアーで寄ってたかって設計す るのである。エンジン、トランスミッション、ブレーキ、居住空間、タイヤ、オーディオ 機器、空調機器、操作パネル、サスペンション他のように、部品ごとに設計を担当するの である。重要なことは、部品単位、はっきりと区分けをして設計をすることです。

部品ごと設計を行うが、それぞれの接続に関しては、予め決めておく必要がある。 たとえば、エンジンとトランスミッションでは、その接続方法を決めてから、各々設計に かかる。そうしないと、最後に組み合わせるときに、それぞれの部品が接続できないとい うことになりかねない。

部品ごと設計が終われば、すべてを組み合わせて、自動車の全体の設計が完了である。予めそれぞ れの部品の接続方法が決められているので、ちゃんとした自動車が出来上がる。大雑 把に言うと、自動車の設計は、このようにして行われる。製造もほとんどこれに似ている。 部品をつくり、最後に組み立てて完成である。この方法は、大規模なものを作るとき に行われる一般的な方法で、重要なことは、

である。このように機能別に分けることにより、自動車の設計・製作は格段に分かりやすく なる。全てのことが分かる人が居なくても、みんなで分担して目的の設計ができるのであ る。複雑なことができるのは、機能毎に分担したからである。

ここでは、自動車をエンジンやトランスミッション等、1段階に分けましたが、実際には、 更に細かく分ける。エンジンであれば、ピストンやバルブ、シリンダーと分ける。部品に よっては、更に細かく機能ごとに分けることもある。機能ごとに細かく分けると、一つの 部品がかなり単純になることが分かるでしょう。

プログラムでは、この特定の機能ごとの集まりをサブルーチンという。メインルーチ ンは、プログラム全体を統括しているもの、自動車のフレームみたいなものと考えれば良 いでしょう(ちょっと強引か)。

自動車みたいな複雑な機械も、単純な機能の部品に分解できるのである。単純な部品の設 計は簡単で、誰でもできるようになる。その代わり、その機能だけ分かる人が寄って集っ て設計をするのである。大規模プログラムも一緒で、それは機能毎に分割され、大人数で 寄って集って、コーディングするのである。これで、プログラムを単純な機能に分割する ことが分かったと思う。

実際に仕事をする場合でも、細かい分かりやすい作業に分割することはきわめて重要であ る。アポロ計画が象徴的で、この辺については、授業で話す。

2.4 分かりやすいプログラムを書くには

大量のパーツからできている自動車も機能別の部品に分けることにより、その構造が分かりや すくなる。例えば、エンジン、トランスミッション、サスペンション 等、機能毎に説明されると分かりやすい。一つ一つの部品、例えば、ボルト、ベルト、シャ フトの説明をされても自動車の全体は分からない。自動車の仕組みを分かるためには、機 能毎に理解する方が断然簡単である。

プログラムも一緒である。それを構成する機能の集まりで理解した方が簡単である。 Windowsの4千万行もあるプログラムの各行を説明されても全く分からない。

このことから、機能毎に分けるとプログラムが容易になるとともに、その内容が分かりや すくなることが理解できるであろう。その違いを、図12に示す。このように、機能別に分けることにより、プログラ ムは分かりやすくなる。そして、機能がはっきりすれば分担してプログラムを書くこ ともできる。ただ、自動車では部品間の接続方法を決める必要があったのと同じように、 プログラムでは処理するデータの受け渡しを決めなくてはならない。

図 1: メインルーチンだけのプログラム

\includegraphics[keepaspectratio, scale=0.7]{figure/only_main.eps}
図 2: 機能毎(サブルーチン)に分割されたプログラム。矢印は、デー タの流れをあらわす。

\includegraphics[keepaspectratio, scale=0.7]{figure/with_subroutine.eps}

自動車の部品にはどれも優劣な無いが、プログラムの場合、1つだけ特別な機能のルーチ ンがある。メインルーチン(メイン関数)と呼ばれるものである。これは、最初に実行され るプログラムである。プログラムの場合、1行毎順番に実行されるため、どれから実行す るか決める必要がある。自動車の部品の場合、それぞれが同時に動き機能するため、メイ ンルーチンに対応するものがない。


ホームページ: Yamamoto's laboratory
著者: 山本昌志
Yamamoto Masashi
平成17年1月26日


no counter