第3回:関数 (10/14)


第2回演習:解答例


今日は関数についての演習を行う.

C言語をはじめとするプログラミング言語の仕様には,繰り返し現れる処理や頻繁に使われる処理を一箇所にまとめ,効率の良い記述を行う方法が用意されている. 今日の演習で取り上げるこの仕組みは関数と呼ばれる. (BASICやFORTRANなど他の言語においてもサブルーチン,プロシージャと呼ばれる類似の機能が用意されている)

今までの演習で用いてきたC言語の printf(), scanf(), sqrt(), getchar() は,実は全て関数である. これらは「ライブラリ関数」と呼ばれ,C言語のコンパイラ(この演習で用いているのはBorland C)にあらかじめ付属しているものであり,必要な#include文の記述により,プログラム中から自由に呼び出すことができる.

そしてmain()も実は関数であるが,「この関数から全体の処理が開始される」ものとして規定されている.

したがって,C言語のプログラムは関数の集合であるといえる. 関数はソースコード中においていくつも,何度も呼び出すことができる. 今回は関数を「作る」演習を行う.


関数とは

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

例:二つの数a,bを渡すと,aのb乗とbのa乗を計算してその和を返し,表示するプログラムを作ってみよう
ただし,整数乗の和を計算する.(pow関数を忘れた時に使える)

関数なし 関数版

#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);
}

ソースコード中に赤字で示した部分に注意.関数を使う場合は,べき乗を計算する箇所が「bekijo」という名前の関数の呼び出しになっている.

ここで「bekijo」という名前の関数は,ソースコード上方で定義しており,整数型の「引数」を2つとり,整数型の「戻り値」を返す関数としている.

なんだかmain文がすっきりしたような気がする.

では,関数の作り方について説明する.


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

ここでは,上の例をもとに整数型の引数を2つとり,整数型の戻り値を返す関数の場合:


int bekijo (int c , int d)
{
    int i,keisan=1;
    for(i=0;i<d;i++){
		keisan *= c;
			}
	return keisan; 
}

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

関数の書き方のルール


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

  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);
}

演習課題

(1)キーボードから長方形の二辺の長さ(整数)を入力すると,面積を計算し画面に出力するプログラムを作成せよ.

(2)(1)を利用して,面積を計算し画面に出力するプログラムを関数を用いて作成せよ.
ただし,引数2つ,戻り値ありとする.

(3)(2)を利用して,二辺の長さを実数にしたときのプログラムを作成せよ.

(4)(2)を利用して,戻り値なしで計算結果を表示するプログラムを作成せよ.

(5)自然数 n の階乗 n! を求めるプログラムを,関数を用いて作成せよ.但し,0! = 1 である.(注:C言語では「!」は否定を表す演算子)
ヒント:まず作成する関数の引数の「型」と「個数」,戻り値の「有無」,「型」を検討しよう.

(6)(5)の関数を利用して,キーボードから自然数 n, r を入力すると,n 枚のカードから r 枚選ぶ組み合わせの数を求めるプログラムを作成せよ.
ヒント:①まず, n >= r である必要がある.②nCr = n! / ((n-r)! r!)

授業終了時までのプログラムと完成した提出用プログラムをoh-meijiシステムを使って提出すること.
授業終了時に送るのは出席の確認用であり,完成した課題は提出用の回に送ること.
(提出期限を厳守し,提出用の回に提出しないと採点を行わない)