7. 関 数 −その1−
 7.1 まずは,数学関数の復習から
 先に,「2.簡単なプログラム」で数学関数の使い方を説明しました.ここでもう一度,思い出してみましょう
C言語では,数学関数は,次のように定義されていました.
     double sin( double x)
     double pow( double x, double y)
      ...
ここで,pow()関数を例に再度説明すると,
   double pow( double x, double y )
    (1)   (2) (  (3) ,    (4)   )
    (1)戻り値の型    POW()関数が返す計算結果の型
    (2)関数名       関数の名前
    (3)引数とその型   POW()関数へ渡す数値(または変数)とその型
    (4)引数とその型   POW()関数へ渡す数値(または変数)とその型

また,数学関数の使い方は,次のようなものでした.

 プログラム例 7.1.1  実行結果
#include <stdio.h>
#include <math.h>
void main(void){
  double x, y, z;

  x = 123.4; y = 1. / 3. ;
  z = pow( x, y );  /* 関数呼び出し */
  printf("%7.2fの立方根は%10.4fです.\n", x, z);
}
 123.40の立方根は  4.9785です.


 7.2 私たちも関数を作ってみよう!
 これまで,いくつかの数学関数を紹介しましたが,ここまでに登場した数学関数は,出来合いの関数でした.しかし,このような関数は自分で作ることもできます.
 実は,C言語のプログラムは,多数の関数で構成します.C言語の関数は,数学関数のような計算をする機能を持つものだけでありません.一般的な話をするには,現段階では知識不足です.
今後,何段階かにわけて,関数を使ってプログラムを構成する方法を説明します.

まずは,計算機能をもつ関数を例に第1段階の勉強をしましょう.
 あまり実用性はないですが,2数の和を計算してくれる関数を例に関数の作成法を説明します.関数の名前は,作成する人が適当に決めればよいのですが,なるべくその機能がわかるような名前を付けると便利です.ここでは,作成する関数の名前をwa()とします.次のプログラムを見て,関数の作り方の理解を試みてください.


 プログラム例 7.2.1  実行結果
#include <stdio.h>

/* 1)次の行は関数 wa() のプロトタイプ宣言 */
double wa(double x, double y);

void main(void){
  double a, b, c;

  a = 1.234;  b = 6.789;
  c = wa( a, b );  /* 2)関数waの呼び出し */
  printf("%7.3f +%7.3f = %7.3f\n", a, b, c);
}

/*  3)関数wa()の本体(定義部) */
double wa( double x, double y){
  double z;
  z = x + y;
  return z;  /* 4)計算結果を返し,終了 */
}
  1.234 +  6.789 =   8.023


 関数を作成し実行するには,プログラム中に次の1)から4)までの赤で書いた記述が必要です.
   /* 1) 関数のプロトタイプ宣言 */
   double wa(double x, double y);
   void main(void){
     ............;
     ............;
     c = wa( a, b ); /* 2) 関数呼び出し(実行) */
     ............;
   }
   /* 3) 関数wa()の本体(定義部) */
   double wa( double x, double y){
     ......... ;
     ......... ;
     return z;  /* 4) 計算結果を返し,終了 */
   }

 1)は,プロトタイプ宣言といい,コンパイラーに「このプログラム中には,次のような関数が登場します.」ということを
  前もって教えておきます.
 3)は具体的な処理を記述した関数本体です.
 4)関数本体には,本体内での処理結果(計算結果)をreturn文で返します.
 2)コンピュータは,main()関数に記述された内容だけを実行します.したがって,関数本体を書いておくだけでは,関
  数は実行されません.関数を実行するには,main()関数の中から直接あるいは,間接(後で説明)的に作成した関数
  を呼び出さなくてはなりません.これを関数呼び出しといいます.
  このプログラム例ではc=wa(x,y)の行で関数呼び出しを行っています.


 7.3 戻り値の型と引数の型
 前節7.2では,戻り値も引数もdouble型の関数を作成しましたが,戻り値や引数はdoubleだけとは限りません.この先,C言語に関する知識が増えるに従って,様々な戻り値や引数が登場します.
 たとえば,前節の関数wa()を書き換えて,次のように整数演算専用の関数を作成することも出来ます.
プロトタイプ宣言,関数呼び出し,関数本体などについて,プログラム例7.2.1と比較して見てください.

 プログラム例 7.3.1  実行結果
#include <stdio.h>
int wa( int x, int y);
void main(void){
  int a, b, c;

  a = 1234;  b = 6789;
  c = wa( a, b );
  printf("%7d +%7d = %d\n", a, b, c);
}

int wa( int x, int y){
  int z;
  z = x + y;
  return z;
}
   1234 +   6789 = 8023


 7.4 もちろん,関数は何個でも作れます
 当然のことながら,プログラム中では必要に応じて何個でも関数を作れます.また,関数average()を見ればわかると思いますが,引数の型と戻り値の型とが一致している必要もありません.
ここで,ひとつだけ気が付いて欲しいことがあります.引数は何個でも渡すことが出来ますが,関数からの戻り値は1個だけだと言うことです.


 プログラム例 7.4.1  実行結果
#include <stdio.h>
int wa( int x, int y);
int sa( int x, int y);
double ave( int x, int y);

void main(void){
  int a, b, c;
  double d;

  a = 123;  b = 678;
  c = wa( a, b );
  printf("%4d +%4d = %4d\n", a, b, c);
  c = sa( a, b );
  printf("%4d - %4d = %4d\n", a, b, c);
  d = ave( a, b );
  printf("(%4d +%4d)の平均 = %7.2f\n",a,b,d);
}

int wa( int x, int y){
  int z;
  z = x + y;
  return z;
}

int sa( int x, int y){
  int z;
  z = x - y;
  return z;
}

double ave( int x, int y){
  double z;
  z = (double)(x + y) / 2.;
  return z;
}
 123 + 678 =  801
 123 -  678 = -555
( 123 + 678)の平均 = -555.00


上のプログラムを次のように書き変えてみました.違いはprintf()文中に関数呼び出しが記述されているところです.戻り値をそのままプリントしていることになります.これまでの知識で理解できますよね.


 プログラム例 7.4.2  実行結果
#include <stdio.h>
int wa( int x, int y);
int sa( int x, int y);
double ave( int x, int y);

void main(void){
  int a, b;

  a = 123;  b = 678;
  printf("%4d+%4d = %4d\n", a, b, wa( a, b ));
  printf("%4d-%4d = %4d\n", a,b,sa( a, b ));
  printf("(%4d +%4d)の平均=%7.2f\n",a,b,ave(a,b));
}

int wa( int x, int y){
  int z;
  z = x + y;
  return z;
}

int sa( int x, int y){
  int z;
  z = x - y;
  return z;
}

double ave( int x, int y){
  double z;
  z = (double)(x + y) / 2.;
  return z;
}
 123 + 678 =  801
 123 -  678 = -555
( 123 + 678)の平均 = -555.00


 7.5 戻り値のない関数
 これまでの例では,関数は計算処理のみをするものとのイメージを持ったかも知れませんが,C言語の関数は,その中でどのような処理をしても構いません.試しにプログラム例7.3.1にprintf()文を組み込んでみたのが次のプログラム例7.5.1です.
 ここで,注意して欲しいのは,関数本体内部で結果の表示までの処理を済ませているため,main()関数では 結果の表示は不要ということです.したがって,関数wa()を呼び出したmain()側へ値を返す必要がないと言うことになります.
このような関数は,次のように定義します.
    void wa( int x, int y)
ここで赤で書いたvoidは戻り値がないことを意味する型宣言子です.(英語で「空っぽ」あるいは「なし」という意味).
この様な関数をvoid型(ボイド型)の関数と呼びます.
関数の戻り値の型がvoidであることに加え,次の点にも気をつけてプログラムをながめてください.
  1)関数呼び出し時に結果を受け取る変数が不要
  2)関数内部で呼び出し側へ結果を返すreturn文が不要

 プログラム例 7.5.1  実行結果
#include <stdio.h>
int wa( int x, int y);
void main(void){
  int a, b;

  a = 123;  b = 678;
  wa( a, b );
}

void wa( int x, int y){
  int z;
  z = x + y;
  printf("%4d +%4d = %4d\n", x, y, z);
}
 123 + 678 =  801
  


ついでに,7.4.1も書き換えてみます.あらたな文法が登場するわけではありませんので,理解を試みてください.


 プログラム例 7.5.2  実行結果
#include <stdio.h>
void keisan( int x, int y);
void main(void){
  int a, b;

  a = 123;  b = 678;
  keisan( a, b );
}

void keisan( int x, int y){
  int z;
  double d;

  z = x + y;
  printf("%4d +%4d = %4d\n", x, y, z);
  z = x - y;
  printf("%4d - %4d = %4d\n", x, y, z);
  d = (double)(x + y) / 2.;
  printf("(%4d +%4d)の平均 = %7.2f\n",x,y,d);
}
 123 + 678 =  801
 123 -  678 = -555
( 123 + 678)の平均 =  400.50  


 7.6 引数のない関数
 戻り値のない関数を紹介しましたが,引数のない関数もあります.プログラム例7.6.1は,title()という引数の不要な関数を作ってみた例です.ここまでの知識で十分理解できると思いますので説明は省略しますがプロトタイプ宣言や呼び出し時の引数の書き方に注意して眺めてみてください.
 プロトタイプや関数定義部には引数の()内には,次のようにvoidと書きます.
  void title(void)
 関数呼び出しのときは,引数には何も書きません.
  title();


 プログラム例 7.6.1  実行結果
#include <stdio.h>
void title( void);
void keisan( int x, int y);
void main(void){
  int a, b;

  title();
  a = 123;  b = 678;
  keisan( a, b );
}
void title(void){
  printf("2数の和と差の計算\n");
}

void keisan( int x, int y){
  int z;
  z = x + y;
  printf("%4d +%4d = %4d\n", x, y, z);
  z = x - y;
  printf("%4d - %4d = %4d\n", x, y, z);
}
2数の和と差の計算
 123 + 678 =  801
 123 -  678 = -555
  


 7.7 関数から関数を呼び出す
 関数は,main()関数のみからではなく,関数どうしで呼び出すこともできます.次の例では,main()関数から呼び出されたkeisan()関数から,title(),wa(),sa()などの関数を呼び出しています.

 プログラム例 7.7.1  実行結果
#include <stdio.h>
void title(void);
void keisan(int x, int y);
int wa( int x, int y);
int sa( int x, int y);
void main(void){
  int a, b;

  a = 123;  b = 678;
  keisan( a, b );
}
void title(void){
  printf("2数の和と差の計算\n");
}

void keisan( int x, int y){
  int z;
  title();
  z = wa(x , y);
  printf("%4d +%4d = %4d\n", x, y, z);
  z=sa(x, y);
  printf("%4d - %4d = %4d\n", x, y, z);
}

int wa(int x, int y){
  return (x + y);
}

int sa(int x, int y){
  return (x - y);
}
2数の和と差の計算
 123 + 678 =  801
 123 -  678 = -555
  


 7.8 同じ関数を何度も呼び出す
 関数は,何度も呼び出すことが出来ます.次の例はあまりにも単純ですが...

 プログラム例 7.8.1  実行結果
#include <stdio.h>
void keisan( int x, int y);
void main(void){
  int a, b;

  a = 123;  b = 567;
  keisan( a, b );
  a = 234;  b = 678;
  keisan( a, b );
  a = 456;  b = 789;
  keisan( a, b );
}

void keisan( int x, int y){
  int z;
  z = x + y;
  printf("%d + %d = %d\n",x,y,x+y);
}
123 + 567 = 690
234 + 678 = 912
456 + 789 = 1245