• 検索結果がありません。

6 関数 6-1 関数とは少し長いプログラムを作るようになると 同じ処理を何度も行う場面が出てくる そのたびに処 理を書いていたのでは明らかに無駄であるし プログラム全体の見通しも悪くなる そこで登場す るのが 関数 である 関数を使うことを 関数を呼び出す ともいう どのように使うのか 実際に見て

N/A
N/A
Protected

Academic year: 2021

シェア "6 関数 6-1 関数とは少し長いプログラムを作るようになると 同じ処理を何度も行う場面が出てくる そのたびに処 理を書いていたのでは明らかに無駄であるし プログラム全体の見通しも悪くなる そこで登場す るのが 関数 である 関数を使うことを 関数を呼び出す ともいう どのように使うのか 実際に見て"

Copied!
7
0
0

読み込み中.... (全文を見る)

全文

(1)

#include <stdio.h> int max(int a, int b) { int m; if (a > b) { m = a; } else { m = b; } return m; } main( ) { int n1, n2, dai; printf(“整数を二つ入力してください。¥n”); printf(“整数 1:”); scanf(“%d”, &n1); printf(“整数 2:”); scanf(“%d”, &n2); dai = max(n1, n2); printf(“大きい方の数字は%d です。¥n”, dai); }

6関数

6-1 関数とは

少し長いプログラムを作るようになると、同じ処理を何度も行う場面が出てくる。そのたびに処

理を書いていたのでは明らかに無駄であるし、プログラム全体の見通しも悪くなる。そこで登場す

るのが「関数」である。関数を使うことを、

「関数を呼び出す」ともいう。

どのように使うのか、実際に見てみよう。次のプログラムは、2 つの数字のうち、大きい方を求

めるものである。

「#include」の行と「main」の行にはさまれた

のが関数部分である。

・最初の「int」は、「int 型の値を返しますよ」と

いう宣言。値を返さない場合もあるが、それは後

ほど。

・次の「max」が関数の名前。

・関数名のあとの( )の中は、

「呼び出し元からこう

いう変数を受け取ります」という意味。これを「仮

引数(かりひきすう)」という。仮引数は、ここで型

宣言する必要がある。仮引数のない関数もあるが、

それも後ほど。

次の{ }内(ブロック内)が関数が行う処理の内容

である。ここは、

main とほぼ同じであるが、いく

つか注意点がある。

①仮引数は型宣言済みと考えて良いので、ブロッ

ク内で改めて宣言する必要はない。

②関数で新たに決める変数の名前は、呼び出し元

の名前とかぶっても構わない。別物として扱われる。

③値を返す場合は、return に続けて返す値を明示する。ここでは変数が返されているが、定数で

も構わない。

この例を詳しく見てみよう。最初の行は「この関数は”max”という名前で、int 型の二つの値を

受け取り、それを使って

int 型の値を返します」という意味になる。

int

max

(int a, int b)

返す値の型

関数の名前

呼び出し元から受け取った値

次に、a,b はすでに宣言済みなので、新たに必要な m だけ定義しておく。m には、a と b の内の

大きい方(正確には a=b のときは b)が代入される。

(2)

/* 引数のない関数 ( ② ) の例 */ #include <stdio.h> #include <stdlib.h> #include <time.h> /* 1 から 100 までの乱数を発生して返す 関数 */ int int_rand( ) { return rand() % 100 + 1; } main( ) { int num; srand(time(NULL)); num = int_rand( ); printf ( “乱数:%d¥n”, num); }

では、

main の方では関数をどのように使っているのか。利用しているのは、

「dai = max(n1, n2);」

の部分。関数呼び出し部と、関数本体の関係は次のようなイメージ。

「max(n1, n2)」で、関数 max に n1 と n2 を渡

して処理してもらう。この

n1 と n2 を「実引数(じ

つひきすう)」と呼ぶ。max 関数はそれを受け取り、

m を返す。言い換えれば m= max(n1, n2)とも言

え、すなわち

dai =m(関数 max 内での)。

ここで見て欲しいのが、main で関数に渡した

変数の名前と、関数で受け取った関数の名前が違

うということ。呼び出し元から関数に送るのは値

そのものであり(現段階では)、変数名は便宜上の

ものと考えていい。もちろん同じでもいいが、同

姓同名の別人だと思って欲しい。

引数と仮引数の対応についての注意。

引数と仮引数は、個数、並び順、型がすべて同じ

でなくてはならない。

次に、戻り値と引数(仮引数)に付いてみていこう。上の例では、引数があって戻り値もあったが、

処理内容によってはどちらとも無くてもよい。したがって、次の

4 通りが考えられる。ちなみに、

戻り値がないときの型宣言は「void」とし、引数がないときは( )内をからにしておく。

① 戻り値、引数ともにある …… type name(仮引数) { }

② 戻り値のみある …… type name ( ) { }

③ 引数はあるが、戻り値はない…… void name(仮引数) { }

④ 戻り値、引数ともに無い …… void name ( ) { }

①はすでに登場したので、②~④の実例を見てみよう。

左のプログラムにある関数は、1~100 の整数の(疑

似)乱数を発生させるものである。

乱数を発生させるコマンドが「rand( )」の部分で、C

言語では一般的に

0~32767 までの整数を返す。rand( )

を使用するためには、

「stdlib.h」が必要となる。

rand ( ) %100 で 100 で割った余りが求まるので、0

~99 が得られる。それに 1 を足せば、1~100 が得られ

ることになるので、それを返す。

main 内の「srand(time(NULL));」は、乱数の種を

初期化するためのおまじないみたいなものだと思って

欲しい。ここで

time( )を使っているので、

「time.h」が

必要となる。乱数を使うときの定番として覚えておく

といい。

(3)

/* 引数があって戻り値のない関数 ( ③ )の例 */

#include <stdio.h>

/* 指定した文字を、指定回数繰り返し表示する 関数 */

void show(char c, int n ) { int i; for (i = 0; i < n; i++) { printf(“%c”, c); } printf(“¥n”); } main( ) { int num; char moji;

printf(“出力する文字:”); scanf(“%c”, &moji); printf(“出力する回数:”); scanf(“%d”, &num); show(moji, num); } /* 引数も戻り値もない関数( ④ )の例 */ #include <stdio.h> /* 時間稼ぎの関数(一定時間何もしない) */ void timer( ) { int i; for (i = 0; i < 10000; i++) { printf(“¥r”); } printf(“¥n”); } main( ) { printf(“明日は¥n”); timer( ); printf(“晴れです。¥n”); } #include <stdio.h> void swap(int a, int b ) { int t; t = a; a = b; b = t; } main( ) { int a = 5, b = 10; swap(a, b); printf(“a=%d b=%d¥n”, a, b); }

このプログラムは

main で文字と数値を代入

し、それを関数に送って文字を指定回数表示させ

ている。関数は表示を行うだけなので、戻り値は

ない。

最後は、引数も戻り値もない例。このプログラ

ムを実行すると「明日は」と表示した後、ちょっ

と間をおいて「晴れです。

」と表示する。

関数では

1 万回「¥r」を表示しているが、見

た目は何もしてないように見える。時間稼ぎなの

で「printf」は無くてもいいのだが、本当に何も

しないと処理時間が短すぎるのでこうしてみた。

6-2 実引数と仮引数の関係

先に、関数が受け取る仮引数は、値そのものと書いた。言

い換えれば、コピーを渡すと考えてもいい。次のプログラム

は、関数で変数の値を交換しようとして作った。実行すると

どうなるか。値は変化していないはずである。というのも、

関数にはコピーを送っただけで、本体の変数は何もいじって

いないからである。これを思った通りの動きをさせるために

は、ポインタの知識が必要となる。

(4)

#include <stdio.h> int max(int ten[ ]) { int max, i;

max = ten[0];

for (i = 1; i < 5; i++) {

if (ten[i] > max) max = tem[i]; } return max; } main( ) { int point[5] = {10 , 90 , 75 , 45 , 80}; printf(“最高点は%d です¥n”, max(point); } #include <stdio.h> void init(int ten[ ]) { int i; for (i = 1; i < 5; i++) { ten[i] = 0; } } main( ) { int point[5] = {10 , 90 , 75 , 45 , 80}; int i; init(point); for (i = 0; i < 5; i++) { printf(“point[%d] = %d”, i, point[i]); }

6-3 配列を引数にする

配列を引数とするときは、次のような書き方をする。

仮引数で、配列の宣言をする。1 次元配列の場

合は、要素数を省略できる。多次元配列でも、最

初の要素数だけは省略できるので、int num[ ][3]

のような書き方ができる。実引数は

1 次元でも多

次元でも、配列名だけを書けばよい。

上の例では配列の値を利用するだけで、配列そ

のものへの変更を加えていない。では、左のよう

なプログラムを実行したらどうなるか。下の実行

結果が示すとおり、すべて

0 になってしまう。

というのも、普通の変数の場合は値のコピーを渡していたが、配列の場合は、配列そのものを渡

しているようなものとなる(厳密には違うが、これを正確に理解するためにはポインタの知識が必

要)。したがって、引数として配列を使う場合には、十分注意が必要となる。

6-4 関数プロトタイプ

多くの入門書では、関数を使う場合

main の前に関数を置いていると思う。関数の置き方はもう

一つ、

main の後に置く方法もある。この場合、関数プロトタイプといって、使用する関数の名前、

戻り値、仮引数を

main の前に宣言する必要がある。書式は次の通り。

int

max

(int a, int b)

返す値の型

関数の名前

呼び出し元から受け取る値

関数の

1 行目と同じ書き方だが、最後に「;」を付けるのを忘れないこと。また、仮引数の名前

は、実際の関数で使う名前と違っても構わない。関数プロトタイプで分かり易い名前を使って、関

数の方では短い名前を使うというのも一つの手である。

実行結果 point[0] = 0 point[1] = 0 point[2] = 0 point[3] = 0 point[4] = 0

(5)

さて、関数を前に置くのと後に置くのでは、どちらがよいのだろうか。小さなプログラムの場合

は、前に置いた方が関数プロトタイプを記述しない分、楽ではあるが、正当とされているのは後に

置く方法である。関数を前に置く方法だと、

・互いに呼び合う関数の記述ができない。

・呼ばれる関数を先に記述しなければならないため、関数のリスト上の出現順序が不自然になる。

・機能ごとに並べたり、abc 順に並べたりできない。

・他人のプログラムと異なったスタイルになる。

といった不利が生じる。また関数プロトタイプを記述することにより

・プログラムの先頭部分を見るだけで、そのプログラムの中で使われている関数の一覧情報が分る。

というメリットがある。

(6)

次のプログラムは、配列要素内の数だけ指定した文字を表示するプログラムだが、 いくつか間違いがある。その間違いを修正せよ。

#include <stdio.h> int show(char ch, int a) { int i, j; for (i = 0; i < 5; i++) { printf(“a[%d]:”, i); for (j = 0; j < a[i]; j++) { printf(“%d”, ch); } printf(“¥n”); } } main() { int i; int num[5] = {5, 4, 0, 3, 7}; char moji = „*‟; Show(num, moji); } 問題 6-2 次のプログラムの□内を埋めよ。 #include <stdio.h> /* 平均を求めて返す関数 */

① heikin( ② kei, ③ num) { return kei / num;

} main() { int i;

int point[5] = {25, 50, 80, 10,100};

double total = 0.0, ave; /* total:合計 ave:平均 */ for (i = 0; i < 10; i++) { total += ④ ; } ave = ⑤ ; /* ave に関数を使って平均を代入する */ printf(“合計:%3.0f 平均:%5.1f¥n”, ⑥ , ⑦ ); } 問題 6-1 実行結果 a[0] :***** a[1] :**** a[2] : a[3] :*** a[4] :*******

(7)

<解答>

#include <stdio.h>

/* 平均を求めて返す関数 */

① double heikin( ② double kei, ③ int num) { return kei / num;

} main() { int i;

int point[5] = {25, 50, 80, 10,100};

double total = 0.0, ave; /* total:合計 ave:平均 */ for (i = 0; i < 10; i++) {

total += ④ point[i] ; }

ave = ⑤ heikin(total , 5); /* ave に関数を使って平均を代入する */ printf(“合計:%3.0f 平均:%5.1f¥n”, ⑥ total , ⑦ ave ); }

問題 6-1

#include <stdio.h>

int show(char ch, int a[ ]) { /* 配列を受け取るので、仮引数も配列 */ int i, j; for (i = 0; i < 5; i++) { printf(“a[%d]:”, i); for (j = 0; j < a[i]; j++) { printf(“%c”, ch); /* 文字を表示するので、%c */ } printf(“¥n”); } } main() { int i; int num[5] = {5, 4, 0, 3, 7}; char moji = „*‟;

show(moji, num); /* 名前は、大文字小文字を区別。引数の並びが違う */

}

参照

関連したドキュメント

子どもたちは、全5回のプログラムで学習したこと を思い出しながら、 「昔の人は霧ヶ峰に何をしにきてい

   遠くに住んでいる、家に入られることに抵抗感があるなどの 療養中の子どもへの直接支援の難しさを、 IT という手段を使えば

いてもらう権利﹂に関するものである︒また︑多数意見は本件の争点を歪曲した︒というのは︑第一に︑多数意見は

以上の基準を仮に想定し得るが︑おそらくこの基準によっても︑小売市場事件は合憲と考えることができよう︒

神はこのように隠れておられるので、神は隠 れていると言わない宗教はどれも正しくな

これも、行政にしかできないようなことではあるかと思うのですが、公共インフラに