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


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

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


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


関数とは

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

3-1

例:二つの数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);
}

演習課題

(1)キーボードから整数を入力すると,その数の2乗を計算し画面に出力するプログラムを作成せよ。

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

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

(4)関数へは,数字しか渡すことはできない。これまで使ってきたprintf()関数で,配列を関数に渡す方法はすでに学んでいた。先週のアドレスとポインタ変数を参考に,関数へ配列に入ったデータをまとめて渡す方法を考え,答えなさい。

void main()
{
	char a[]="abc"; 
	printf("%s", a);   /* 関数へ,文字列(文字の配列)を渡している。ここで渡しているのは何でしょう? */
} 

(5)関数からは,数字を一つだけしか戻すことはできない。これまで使ってきたscanf()関数では,関数から戻り値を用いないで数字や文字列を受け取ることができていた。先週のアドレスとポインタ変数を参考に,数字や配列を,戻り値を用いないで受け取る方法を考え,答えなさい。

void main()
{
	int a;
	char str[100];

	scanf("%d", &a);   /* 関数で,入力された値が変数aに入力される。ここで関数に渡してるのは何でしょう? */
	scanf("%s", str);   /* 同様に,文字列が入力される */
} 

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