関数というものは、まず数学で学習する。入り口と出口に注目すれば、関数というのは一 定の個数の値を受け取って,それから決まる値を返す箱2のようなものである。その箱は、 特定の機能を果たす。数学では、
(1) |
C言語の関数は数学の関数と似ている。先ほどの数学の例に倣うと、C言語では
y=f(x1, x2, x3, ... , xn)と記述する。数学では を変数と呼ぶのに対して、C言語を含む手続き 型プログラム言語では x1, , xn を引数(ひきすう)と呼ぶ。また関数が返す値 を戻値(もどりち)と呼ぶ。これは、関数fが引数x1, x2, x3, ... , xnの値を 受け取って、定義された処理を実施し、戻り値を計算する。その戻り値は、代入演算子 (=)により、変数yにコピーされると解釈する。
全ての関数はどれも優劣が無く、同じレベルにある。それぞれの関数は、互いに呼び出す ことにより、それ固有の処理を行う。そして、実際の処理の内容を表す実行文は、どれか の関数に含まれる。従って、処理の内容は関数の中に書かなくてはならない。
ただし、同じレベルにあるが、main関数だけは、少しだけ優位な立場にいる。全て の関数に全く優劣が無ければ、どこからプログラムを実行する順序を決めることができな い。そのため、main関数だけ、少し優先順位が高く、最初に実行されることになっ ている。
まとめると、関数というのは呼ばれると何らかの仕事をするプログラムのことである。こ れは一つの大きなプログラムの部品と考えてよい。この関数を用いることにより、プログ ラムを機能毎に分割できる。そうすることにより、
このプロトタイプ宣言の書き方は、簡単で、実際には関数の定義の先頭部分をコピーして、 セミコロンをつければ良い。
プロトタイプ宣言を書くことにより、ソースプログラムを読みやすくなります。現在では、複 数のプログラマーによりひとつのプログラムが作成されるため、読みやすいあるいは分か り易いプログラムを書くことは重要である。
プロトタイプ宣言をまとめると
関数の定義をまとめると、次のようになる。
よく使われる処理は、関数にまとめ、必要なときにコールすれば良い。このように、よく 使われる処理をまとめると、プログラムの内容が分かり易くなる。関数は、まことに便利 な機能である。
#include <stdio.h> void hello(void); /* プロトタイプ宣言 */ /*================================================*/ /*======== メイン関数 =============*/ /*================================================*/ int main(void){ int i; for(i=0; i<100; i++){ hello(); /* 関数呼び出し */ } return 0; } /*================================================*/ /*======= 関数 ==============*/ /*================================================*/ void hello(void){ printf("Hello World \n"); }
(2) |
#include <stdio.h> #include <math.h> double function1(double x); /* プロトタイプ宣言 */ double function2(double x); /* プロトタイプ宣言 */ /*==============================================================*/ /* main function */ /*==============================================================*/ int main(void){ int kakudo; double pi, theta, y1, y2; pi=3.141592; for(kakudo=0; kakudo<=360; kakudo++){ theta = kakudo*pi/180.0; y1 = function1(theta); /* 関数呼び出し */ y2 = function2(theta); /* 関数呼び出し */ printf("%d\t%lf\t%lf\n", kakudo, y1, y2); } return 0; } /* <<<<<<<<<< これ以降は、サブルーチン >>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ /*==============================================================*/ /* sin(2x)の計算 */ /*==============================================================*/ double function1(double x){ double y; y=sin(2.0*x); return y; } /*==============================================================*/ /* sin(x)cos(x)の計算 */ /*==============================================================*/ double function2(double x){ double y; y=2.0*sin(x)*cos(x); return y; }
メイン関数とプログラマー定義の関数で同じメモリーにアクセスできれば、問題は解決す る。いろいろな方法があるが、ここでは後に示すプログラムで、参照渡しという技法を使 う。これにより、メモリーの状態が図2のようになる。プロ グラマー定義の関数とメイン関数が同じメモリーを使っているのである。そのため、プロ グラマー定義の関数で、メイン関数の変数の内容を書き換えることができるのである。
参照渡しを実現するためには、呼び出し元の実引数に&をつけ、呼ばれる関数の 仮引数に*をつける。使い方については、プログラムを見て欲しい。
#include <stdio.h> void swap(int *i, int *j); /* プロトタイプ宣言 */ /*==============================================================*/ /* main function */ /*==============================================================*/ int main(void){ int a, b; char temp; printf("a = "); scanf("%d%c",&a, &temp); printf("b = "); scanf("%d%c",&b, &temp); swap(&a, &b); /* 関数呼び出し */ printf("a=%d b=%d\n", a, b); return 0; } /*==============================================================*/ /* データの入れ替え */ /*==============================================================*/ void swap(int *i, int *j){ int temp; temp = *i; *i = *j; *j = temp; }
10人の英語の成績を処理するプログラムを例に示す。これは、10人分のテストの点数を読み込んで、 平均点と各人の平均点からの差を計算するものである。具体的には、次のような動 作をするプログラムである。
これは、非常に簡単で、次のようにする。たとえば、呼び出し元でhoge[100]という 配列を関数kansu()に送りたいのならば、
kansu(hoge);として、コール (call) すれば良い。一方、呼び出された関数側では、それを配列名 fugaとして使いたいならば、
戻り値の型 kansu(fuga[]){ 処理内容 }とする。これは、例のプログラムをよく見て欲しい。このようになっているはずである。
2次元以上の配列の場合も同じようになる。ただし、呼び出された側では、配列のサイズ が必要となる。たとえば、呼び出し元で、
int hoge[100], fuga[200][300], foo[400][500][600]; kansu(hoge, fuga, foo);とする。そうして、呼び出された関数側では、それを配列名a,b,cとして使いたいならば、
戻り値の型 kansu(a[], b[][300], c[][500][600]){ 処理内容 }とする。要するに呼び出された関数側では、配列のサイズの左端を書かなくても良いので ある。書いても良いが、一般的には書かない習慣となっている。書かない方が、間違える 確率が減るからだろう。
#include <stdio.h> int diff_ave(int n, int data[]); /* プロトタイプ宣言 */ /*==============================================================*/ /* main function */ /*==============================================================*/ int main(void){ int seiseki[10], average, i; char temp; for(i=0; i<10; i++){ printf("%d番の成績 = ", i); scanf("%d%c",&seiseki[i], &temp); } average=diff_ave(10, seiseki); /* 関数呼び出し */ printf("平均点 = %d\n", average); printf("平均点との差\n"); for(i=0; i<10; i++){ printf("%d番 = %d\n", i, seiseki[i]); } return 0; } /*==============================================================*/ /* 平気値とその差の計算 */ /*==============================================================*/ int diff_ave(int n, int data[]){ int i, sum, ave; sum=0; /* 初期化 */ for(i=0; i<n; i++){ /* 点数の合計の計算 */ sum = sum + data[i]; } ave = sum/n; /* 平均値の計算 */ for(i=0; i<n; i++){ /* 平均値との差の計算 */ data[i] = data[i] - ave; } return ave; }