第3回:関数(1) (4/25)


第2回演習:解答例


今週は,関数の使い方について勉強します。

キーワード:「関数」「引数」「戻り値」


C言語をはじめとするプログラミング言語の仕様には,繰り返し現れる処理や頻繁に使われる処理を一箇所にまとめ,効率の良い記述を行う方法が用意されている。 今日の演習で取り上げるこの仕組みは関数と呼ばれる。 (BASICやFORTRANなど他の言語においてもサブルーチン,プロシージャと呼ばれる類似の機能が用意されている)
今までの演習で用いてきたC言語の printf(), scanf(), sqrt(), getchar() は,実は全て関数である。 これらは「ライブラリ関数」と呼ばれ,C言語のコンパイラ(この演習で用いているのはBorland C)にあらかじめ付属しているものであり,必要な#include文の記述により,プログラム中から自由に呼び出すことができる。そしてmain()も実は関数であるが,「この関数から全体の処理が開始される」ものとして規定されている。
したがって,C言語のプログラムは関数の集合であるといえる。 関数はソースコード中においていくつも,何度も呼び出すことができる。


関数とは

関数とは,例えて言えば材料(引数,ひきすう)を渡すと,レシピ(関数の定義)に基づいて調理し,料理(戻り値,もどりち)を届けてくれるようなものである。

3-1


課題(1)

たとえば,みなさんになじみの深い三角関数はすでに用意されているので,試しに使ってみよう。以下のプログラムを参考に,角度を0度から360度まで1度ずつ変えたときの,sinの値を各行に出力するプログラムを作成してみよう。sin関数は,求めたい角度をラジアンで関数に入力する(渡す)と,その角度の時のsinの値が戻ってくる。計算上,円周率はpi=3.141とする。


#include <stdio.h>		/*printfなどの命令を使うためのファイルの読み込み*/
#include <math.h>		/*sin関数など数学用の関数を使うためには必ず読み込むこと*/

void main()
{
	double rad,pi;		/*sin(double x)のため,変数xはdouble型で定義すること*/
	double x;
	
	pi=3.141;			/*πの定義*/
	rad = 10.0/180.0*pi;	/*sin関数の引数は,ラジアン[rad]にすること*/
	
	
	x=sin(rad);
	
	printf("角度10°の時のsinの値は%1.3fです。¥n",x);
	
}

結果の例(こんな風に表示されるようにプログラムを考える): 

0.000000
0.017452
0.034898
....


関数の定義

用意された関数を利用するばかりでは,つまらない。ここで,関数の中身はどうなっているのかを,二つの数a,bを渡すと,aのb乗とbのa乗を計算してその和を返し,表示するプログラムで見てみよう。

関数なし 関数版

#include <stdio.h>
 
  
 
 
 
void main()
{
	int a,b,i,wa,bekijo1=1,bekijo2=1;
	
	printf("a=");scanf("%d",&a);
	printf("b=");scanf("%d",&b);

	for(i=0;i<b;i++){		/* a^bの計算 */
		bekijo1 *= a;
	}

	for(i=0;i<a;i++){		/* b^aの計算 */
		bekijo2 *= b;
	}
	
	wa = bekijo1 + bekijo2;
    
	printf("a^b+b^a=%d¥n",wa);    
}

#include <stdio.h>
 
int bekijo(int c,int d) /* べき乗を計算するための関数定義*/
{
	int i,keisan=1;
    
	for(i=0;i<d;i++){
		keisan *= c;
	}
    
	return keisan; /* 値を返すreturn文 */
}
 
void main()
{
	int a, b, wa;
 
	printf("a=");scanf("%d",&a);
	printf("b=");scanf("%d",&b);
 
	wa = bekijo(a,b)+bekijo(b,a); /* 関数を呼び出す */
 
	printf("a^b+b^a=%d¥n",wa);
}

関数なしの場合,aのb乗の計算とbのa乗のようにとてもよく似たプログラムを繰り返し記述している。(無駄な感じ)
関数を使うと,べき乗を計算する箇所が「bekijo」という名前の関数の呼び出しになっており,うまい具合に一つのループで,二通りの計算ができている。 ここで「bekijo」という名前の関数は,ソースコード上方で定義しており,整数型の「引数」を2つとり,整数型の「戻り値」を返す関数としている。


関数の定義のしかた,関数の引数と戻り値

ここでは,上の例をもとに整数型の数を2つ受けとり,計算結果を整数型で一つ返す関数を見てみる。




戻り値の型 関数名(引数1の型 変数名1,引数2の型 変数名2, ...)
{
 
    /*  ここに処理を記述  */
 
    return xxx;    /*  xxxが戻り値  */
}

関数の書き方のルール


関数の呼び出しにともない実行される処理の順序.

3-2

  1. 関数の呼び出し元(ここではmain関数内の bekijo(a, b) の部分)から「引数」a, b を伴って関数waに処理が移る。
  2. 関数が呼び出された時点での変数 a, b の値がコピーされ, c, d として受け取る。
  3. 関数内でいろいろな処理をした後,return文に到達すると,値を返す(return文)動作が行われ,ここで関数の処理が終了する。(return文以降に記述された処理は実行されない)
  4. 関数の戻り値(ここでは関数bekijo 内の return で指定された変数 x の値)を,main内のwaに代入。

処理の流れ,引数(変数)のコピーや,return による値の戻りをよく理解すること。


戻り値や引数を持たない関数の例

関数の役割を考えた時,引数や戻り値が不要な場合が考えられる。そのような場合は voidというキーワードを使う。以下に様々な引数,戻り値の組み合わせを例示する。


#include <stdio.h>
 
/* 引数なし,戻り値無し の関数*/
void moji_hyouji(void)
{
    printf("単なる文字の表示です.¥n");
    return;       /*  戻り値「なし」なので,returnのみ記述する.この場合は省略可  */
}
 
 
/* 引数あり,戻り値無し の関数*/
void wano_hyouji(int a, int b)
{
    int x;
 
    x = a + b;
    printf("二つの数の和は,%dです.¥n", x);
 
    return;       /*  戻り値「なし」なので,returnのみ記述する.この場合は省略可  */
}
 
/* 引数あり,戻り値あり の関数*/
int wano_keisan(int a, int b)
{
    int x;
 
    x = a + b;
 
    return x; /* これは絶対必要! */ 
}
 
void main()
{
    int a, b, sum;
 
    printf("一つ目の数を入力してください:");
    scanf("%d", &a);
    printf("二つ目の数を入力してください:");
    scanf("%d", &b);
 
    moji_hyouji(); 
  
    wano_hyouji(a, b);
 
    sum = wano_keisan(a, b);
    printf("合計は %d です.¥n", sum);
}

演習課題

(2)キーボードから整数を入力すると,その数の階乗(3!なら 3×2×1)を計算し画面に出力するプログラムを作成せよ。(関数を使わないで良い)

(3)(2)のプログラムの,階乗を計算する部分を関数として書き換えよ。

(4)(3)で作成した関数を利用して,1から10の10個の数の階乗の和を求めるプログラムを作成せよ.

(5)関数からは,数字(値)を一つだけしかmain関数に戻すことはできない。複数の数字や配列をmain関数に戻す方法を考え,答えなさい。

(1),(4),(5)を解答用紙に記入し,提出すること。