次のプログラムは任意の点(x1,y1),(x2,y2)の距離の二乗を求めるプログラムです.
#include <stdio.h>
#include <stdlib.h>
void main()
{
int x1,x2,y1,y2,l;
printf( "x1 =" );
scanf( "%d", &x1 );
printf( "y1 =" );
scanf( "%d", &y1 );
printf( "x2 =" );
scanf( "%d", &x2 );
printf( "y2 =" );
scanf( "%d", &y2 );
l = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
printf( "距離は%dです\n", l );
}
次に,上記のプログラムを作った数週間後に,任意の点(a,b)と点(c,c)(c=0〜9)の距離を求める プログラムを作ろうとしたときのことを考えてみます. 下記のように途中までプログラムを作ってみました.
#include <stdio.h>
#include <stdlib.h>
void main()
{
int a,b,c;
printf( "a =" );
scanf( "%d", &a );
printf( "b =" );
scanf( "%d", &b );
for( c = 0 ; c <= 9 ; c++ )
{
}
}
あとは,点(a,b)と点(c,c)の距離を求める文と表示する文を書けばよいわけです. 点と点の距離を求める公式を忘れてしまったため前に作ったプログラムから, カット&ペーストすることにしました.
#include <stdio.h>
#include <stdlib.h>
void main()
{
int a,b,c,l;
printf( "a =" );
scanf( "%d", &a );
printf( "b =" );
scanf( "%d", &b );
for( c = 0 ; c <= 9 ; c++ )
{
l = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
printf( "距離は%dです\n", l );
}
}
しかし,このままでは動きません.なぜなら,前のプログラムの点の距離を求める文は, 点の座標がx1,x2,y1,y2に入っていることを前提にした算術式だからです. きちんと動くようにするためには,
l = (a-c)*(a-c) + (b-c)*(b-c);
とするか,
x1 = a;
y1 = b;
x2 = c;
y2 = c;
l = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
としなければなりません.
このような面倒は,点と点の距離を求める部分を関数化しておくことで,解決ができます. 関数とはある値をいれると,ある値が出てくるブラックボックスのようなものです. 最初のプログラムを二点の距離を求める部分を関数化したプログラムを次に示します.
#include <stdio.h>
#include <stdlib.h>
int length( int x1, int y1, int x2, int y2 )
{
int len = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
return len;
}
void main()
{
int x1,x2,y1,y2,l;
printf( "x1 =" );
scanf( "%d", &x1 );
printf( "y1 =" );
scanf( "%d", &y1 );
printf( "x2 =" );
scanf( "%d", &x2 );
printf( "y2 =" );
scanf( "%d", &y2 );
l = length( x1,y1,x2,y2 );
printf( "距離は%dです\n", l );
}
次に二つ目のプログラムを変更したものを示します.
#include <stdio.h>
#include <stdlib.h>
int length( int x1, int y1, int x2, int y2 )
{
int len = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
return len;
}
void main()
{
int a,b,c,l;
printf( "a =" );
scanf( "%d", &a );
printf( "b =" );
scanf( "%d", &b );
for( c = 0 ; c <= 9 ; c++ )
{
l = length( a, c, b, c );
printf( "距離は%dです\n", l );
}
}
これらのプログラムを見てもらえればわかると思うように, 関数をまるごとコピーしてしまえば, あとは,関数を呼び出すときの引数を書き換えるだけで済みます. 点の距離を求めるくらいでは,あまりありがたみはありませんが, もっとふくざつな処理を関数化しておけば, 後にその処理を使いたくなった場合,容易に流用することができます. また,一つのプログラムの中で,繰り返し同じ処理を使うときも, 関数化しておけば,あとは関数の呼び出しをするだけで済み,便利です.
関数のメリットはもう一つあります. たとえば,y = (a+b)(a+b)/a を計算するプログラムの
x = a + b;
ans = x*x / a;
という部分を,y = (a+b)(a+b)/a*(a*b)を計算するために,カット&ペーストして,
x = a * b;
============ <--- ここ
y = ans * x;
に入れようとすると,y = (a+b)(a+b)/a*(a+b)となってしまい, 意図していた y = (a+b)*(a+b)/a*(a*b) にはなりません. これは,両方で変数 x を使っているからです. きちんと動くようにするためには,どちらかの x を別の変数にする必要があります.
しかし関数を用いるとならば,次にようなプログラムになり,問題はありません.
#include <stdio.h>
#include <stdlib.h>
int func( int a, int b )
{
int x,ans;
x = a + b;
ans = x*x / a;
return( ans );
}
void main()
{
int a,b,x,y;
x = a*b;
y = func( a, b ) * x;
}
つまり,関数内での変数は,関数内だけで閉じていて,その外には影響を与えません. また,
#include <stdio.h>
#include <stdlib.h>
void func( int a )
{
a = 5;
}
void main()
{
int a = 3;
func( a );
printf( "%d", a );
}
としても,画面には 5 ではなく,3 が表示されます. つまり,引数で受け取ったものも関数内で閉じていて,その外には影響を与えません.
先のプログラムでは,座標のx成分とy成分を別々に渡していましたが, このような座標は配列で格納していることが多いので, 先のプログラムを書き換えてみます.
#include <stdio.h>
#include <stdlib.h>
int length( int p1[], int p2[] )
{
int len = (p1[0]-p2[0])*(p1[0]-p2[0]) + (p1[1]-p2[1])*(p1[1]-p2[1]);
return len;
}
void main()
{
int p1[2], p2[2];
printf( "x1 =" );
scanf( "%d", &p1[0] );
printf( "y1 =" );
scanf( "%d", &p1[1] );
printf( "x2 =" );
scanf( "%d", &p2[0] );
printf( "y2 =" );
scanf( "%d", &p2[1] );
l = length( p1, p2 );
printf( "距離は%dです\n", l );
}
n人分の点数を格納した配列と人数nを引数として渡すと,平均点を返す関数を作りなさい. その関数を利用して,平均点を表示するプログラムを作りなさい.