第12回 関数の書き方

このドキュメントは http://icrus.org/c_language_beginers_course/ 上にあります.

[課題12-1]簡単な関数の例を実行しよう.

[プログラム例12-1]


01: #include <stdio.h>
02: void main(void){
03:   void func(void);
04:
05:   func();
06:   getchar();
07:  }
08:
09:  void func(void){
10:  printf( "hello,c from func.\n" );
11:  return;
12: }

行説明
03行目→関数func()の戻り値の型と引数の型を宣言します.この場合戻り値,引数ともに無し(void型)で宣言しています.
05行目→関数func()を呼び出します.
09~12行目→関数func()の本体ブロックです.
09行目→03行目と同様に今度は本体の方で,関数の戻り値と引数を宣言しています.
11行目→文return;により,呼び出された関数に戻ります.

[結果12-1]

コンパイル・実行すると次のよう表示されます.

hello,c from func.

リターンキーを押すとプログラムは終了します.

 関数func()の機能は標準関数printf()を実行するだけです.基本的には,3行目のように①これから使おうとする関数を戻り値の型と引数の型といっしょにして宣言し,②本体をコーディングするだけです.宣言と戻り値,引数についてこれから理解すれば,その他はいままでやってきたC言語の文法とかわるところはありません.
 関数本体は,関数main()の前にあっても,後ろにあっても,別なファイルにあっても構いません.(別なファイルにある場合は,コンパイルのほかにいくつかの作業が必要です.)
 高校の数学で,「関数とは何かを入力すると何かを出力する箱のようなもの」と習った覚えはありませんか.C言語でいう関数もこれと全く同じです.データを引数で入力するとデータを戻り値で返してきます.(プログラム例12-1のように,入出力なしで機能を実行するだけの場合もあります.)C言語の特徴の一つは関数よりコーディング(プログラミング)するところです.
 いままではmain関数の中だけで説明してきました.しかし実際のプログラムは,たくさんの関数から成り立っています.関数を使う利点を一言でいうと「特有の機能を持たせた関数を組み合わせて,プログラミングすることにより,より効率的なシステム開発を実現できる」点にあります.さらに特有の機能に一般性を持たせていけば,他のユーザープログラムも利用でき,さらに効率的です.例えば,printf()などの標準関数はコンパイラの製造販売者が対象のコンピュータにあわせて,コーディングしてくれた関数です.それを全てのユーザーが使用することができます.とても効率的ですね.
 プログラム例12-1ではとりあえず,入出力なしの関数ができあがりました.次からは,入出力を引数,戻り値でコーディングして,本格的関数を作っていきましょう.

[課題12-1]解の公式の計算(プ例3-2)を関数を使ってコーディングしよう.

[プログラム例12-2]


01: #include <stdio.h>
02: #include <math.h>
03: double hanbetsu( double, double, double);
04: void fun_kaiR( double, double, double);
05: void fun_kaiJ( double, double, double);
06:
06: void main(void){
08:     double a, b, c, d;
09:     printf( "ax^2+bx+c=0のときa~cを入力して下さい\n");
10:     printf( "a=" );
12:     scanf( "%lf%*c" , &a);  /* 変数aを入力*/
13:     printf( "b=" );
14:     scanf( "%lf%*c" , &b);  /* 変数bを入力*/
15:     printf( "c=" );
16:     scanf( "%lf%*c" , &c);  /* 変数cを入力*/
17:
18:     d = hanbetsu( a, b, c ); /* 判別式*/
19:     if( d>=0.0 ){
20:         fun_kaiR( a, b, d ); /* 実根を持つとき*/
21:     else
23:         fun_kaiJ( a, b, d ); /* 虚根を持つとき*/
24:     getchar();
25: }
26:
27: double hanbetsu( double a, double b, double c ){/* 判別式 */
28:     return b*b - 4.0*a*c;
29: }
30:
31: void fun_kaiR( double a, double b, double d ){/* 実根を持つとき */
32:     double x1, x2;
33:     printf( "判定式dは0以上です.\n");
34:     x1 = (-b + sqrt( d ))/(2.0*a);
35:     x2 = (-b - sqrt( d ))/(2.0*a);
36:     printf( "x1 = %lf\n", x1 );
37:     printf( "x2 = %lf\n", x2 );
38:     return;
39: }
40:
41: void fun_kaiJ( double a, double b, double d ){/* 虚根を持つとき */
42:     double x, j;
43:     printf( "判定式dは0未満です.\n");
44:     x = (-b)/(2.0*a);
45:     j  = sqrt( -d )/(2.0*a);
46:     printf( "x1 = %lf+%lfj\n", x, j );
47:     printf( "x2 = %lf-%lfj\n", x, j );
48:     return;
49: }

行説明
06~25行→main関数です.
03~05行→関数を宣言しています.
27~29行→変数a,b,cを引数として入力し,判別式の答えを戻り値として返えす関数です.
28行目→式b*b-4.0*a*cの値を返すためのreturn文です.
31~39行→変数a,b,dを引数として入力し,実根を計算し,画面に出力する関数です.
41~49行→変数a,b,dを引数として入力し,虚根を計算し,画面に出力する関数です.

[結果12-2]

コンパイル・実行すると次のよう表示されます.

ax^2+bx+c=0のときa~cを入力して下さい
a=2[リターン印]
b=-8[リターン印]
c=8[リターン印]
判定式dは0以上です.
x1 = 2.00000
x2 = 2.000000

リターンキーを押すとプログラムは終了します.

 アルゴリズムはプログラム例3-2と同じですが,ここでは3つの関数を定義して,解の公式の解法を実現しています.
 注目してもらいたいのは,①引数を3個並べて,main関数から各関数へ渡している点と,②return文を使って値をmain関数へ返している点です.
 各機能を関数に分割したため,main関数が大変すっきりわかりやすくなりました.各関数もそれぞれに特化した役割をはたしていますので,理解は容易だと思います.
なお,main関数の変数名と,各関数の変数名は同じにする必要はありません.例えば,main関数の変数a,b,cと関数hanbetsu()の変数a,b,cは別の変数名にして構いません.

[文法12]

1.関数の基本形


void main(void){
①type 関数名( type, ・・・, type );
②type x, arg1, arg2, ・・・, argn;
③x = 関数名( arg1, arg2, ・・・, argn );
;
↓/* メイン関数の処理 */
;
}

④type 関数名( type arg1, type arg2, ・・・, type arg3 ){
⑤type y;
;
↓/* 各関数の処理 */
;
⑥return y;
}

 (注)・typeは型(charやint,doubleなど)
・arg1~argnは引数名
・x,yは変数名


①関数の型の宣言
(1)これから使う戻り値の関数の型と引数の型を宣言します.
(2)戻り値の型が関数の型となります.
(3)戻り値が不要なときは,void型にして下さい.
(4)引数は引数の個数分,それぞれの引数の型で行って下さい.
(5)引数がいらないときは,void型を一つ記述して下さい.

②関数に渡す変数の宣言
(1)これは,通常のmain関数で使う変数の宣言と同様です.

③関数を呼び出す.
(1)引数を関数宣言で宣言した個数分,関数に渡します.
(2)戻り値(関数の中でreturn分の右に記述する変数yの値)が変数xに代入されます.戻り値が関数名()の値だと考えればよいでしょう.

④関数ヘッダ
(1)関数の型(戻り値の型),関数の名前,引数の型および引数名を書きます.
(2)ここで記述された引数名は,普通に宣言された変数と同様に関数の中で使えます.

⑤戻り値の定義
(1)関数内の普通の変数定義と同じですが関数の値(戻り値の値)と同じで型でなければなりません.

⑥呼び出された関数に戻ります.
(1)return文の右に変数,または式を書けばその値が,関数の値(戻り値)となります.書かなければ,関数の値は不定(どんな値かわからない)となります.
(2)return文の右の変数,式は関数の型と同じ型にすべきです.





このドキュメントは http://icrus.org/c_language_beginers_course/ 上にあります.

2017,1 ssatoh@ 足立工科大学 工学部 情報通信工学科