\CAPTION\ |
\CAPTION\ |
この関数は自分で作ることもできます。
一般に関数は「特定の処理をまとめる」ために作ります。
たとえば、同じ手順を、一連の作業の中で何回も使う場合、毎回同じことを書くのは大変なので、一回関数として書いてしまって、必要なときにその関数で処理する、という使い方です(他のプログラミング言語では「サブルーチン」と呼ばれることもある)。
もう一つは、あまりに手順が長くなりすぎてうっとうしくなったときに、仕事のブロックごとに切り分けるという使い道です。
C言語でプログラムを作る、ということは、大抵は自分の望む機能を関数の形で積み上げていって、処理をさせるということです。
普段、プログラムをつくる際の「int main(void) { ... }」も実は「プログラムが実行されると必ず呼び出される関数」です。
返値はint=整数で、プログラムの実行結果などをプログラム終了後に使うことができるようにする値です(とはいえ、整数1個なので、正常終了したかどうかくらい)。
一方、引数は「void」ですが、これは「なにもなし」を意味します。
つまり、このmain関数は、「引数ゼロ個、返値int」という関数です。
※mainには引数として、実行時のオプションをもらう形式もある。
ちなみに、乱数のところでつかった rand()関数、srand()関数は、
int rand(void) =引数ゼロ、返値int
void srand(unsigned int seed)
=引数1個(unsigned=正の数だけの int)、返値なし
です。rand(10)のように引数voidな関数に値を渡すことはできませんし、逆に返値voidな関数を a=srand(10) のように値として使うことはもちろんできません。
なお、引数はいくらでも増やせますが(システム上の制限はある)、返値は一つだけです。複数の値を返したい場合は、別のテクニックが必要ですが、難易度があがるので、ここでは、扱いません。
実際に、プログラムを作って動かしてみます。
まず、関数は呼び出す前に、その形式が分からないと使えません。
そのため、main で使う前に、その仕様を書いておきます。
※ここでは仕様と中身をまとめて書いているが、仕様だけ先に決めておいて、中身は別途、という書き方もある。
関数は、
関数から値を返すときは、
なお、returnのあとはいくら関数に内容が書いてあっても実行されません。
返す値を決めたけど、まだ後始末がある、という場合は、適当なところに値を補完しておいて、後始末をして、その後でreturnする必要があります。
※処理の内容に応じて、returnは複数あってもかまわない
※returnせずに関数を最後まで実行すると、そこで自動でreturnする
※ただし、返値が変になるのvoid以外の場合は必ずreturnする
関数を使うときは、
上のプログラム例では、main()のなかで y=func(x); という形で、関数が使われています。
ここで、mainの手順は一旦置いておいて、値xを引き継いでfuncを実行します。
funcに入ったら、渡された値(mainではxだった)がaで使えます。
注意点としては、渡された値である、aをfuncの中で別の値にしても、main側のxには何の影響もありません。一般に便利ですが、不便に感じることもあります。
もうすこし厳密には、関数は自分が呼び出されると、真っ先にメモリ上に自分が今、作業するのに必要なメモリを確保します。
そこに変数をおいたりして作業をします。
関数の処理が終わると、そのメモリを捨てて終わります。
「呼び出されたときに」確保するため、「自分で自分を呼ぶ」ということもできます。
まず呼ばれたときに、作業場所を確保します。その作業途中で自分自身を呼び出すと、それまでの場所とは別に新たに場所を確保して作業をします。
これを「再帰呼び出し」といい、ときどき使い道があります。
ここでは、階乗
まず、n!を計算する関数を fact(n)とします。
を求めてみます。
ここで、
なので、
fact(n)=fact(n-1)*n
です。加えて、
1!=1 (そのまま)、0!=1 (期待される性質的に規定)
なので、fact(n)のすべき処理は、
となります。これをプログラムにすると、以下のようになります。
という処理になります。
(1,2,3)(1,2,4)(1,2,5)(1,3,4)(1,3,5)(1,4,5)
(2,3,4)(2,3,5)(2,4,5) (3,4,5)
の10通り
このような組合せの計算は、主に受験数学の「問題のための問題」に使われることが多いのは確かですが、「すべてチェックする」的な作業をするとき、最初に総数を確認しておいて、チェック漏れがないかを確認することにも使えます。
ここでは、「複数の関数をつくる題材」として、計算してみます。
一般に、n個のものから、m個を選び出す組合せの数は、
で計算されます。それを計算する関数 combi(n,m)を作ってみましょう。
複数の引数を持った関数をつくれますし、そこから別の関数を何度も使うこともできます。
この際、自分なりの改造(改造と言えそうな改造)がしてあれば、プラスα評価します。
たとえば、30個の値をまとめて扱いたいという場合に、いちいちバラの変数をa1,a2,a3...のように作っていくのは面倒です。
また、ベクトルの要素や座標のように(x,y,z)は常にセットで使う、という場合もあり、これもまとめておきたいところです。
以下では、そういうデータの扱い方を2種類示します。
といっても、特殊なことはなく、
いまはメモリが潤沢なので、とりあえず使いそうな上限よりも多くの個数をとっておくのは一つの手です。
余裕があれば、forの値の範囲を変えて、「扱いが悪かったとき」どうなるかを試してみると良いでしょう。
なお、このように配列として作った変数x[]は、単にxとして値を参照することはできませんし、同じように作ったy[], z[]に対して、z=x*yとして全部の要素の計算をしてくれたりもしません。forなどで繰り返し計算する必要があります。
構造体は、多少やっかいです。
実際に実用的なプログラムを作る場合には、構造体を構造体に含めることもあります。
この番号は0〜「最初に指定した個数−1」です(ゼロから始まるので、最後が−1される)。
負の値も、指定した個数以上の値もNGです。
それらを使うと、たいていの場合プログラムの誤動作の原因になり、プログラムが強制終了する場合もあります(むしろ、強制終了してもらった方が間違いに気づきやすい)。
(ただし、それを越えたら危険なので、厳密には各種チェックが必要。それを放置したものが、いわゆる「セキュリティホール」の最大の原因)
負の値、たとえば、「−100〜100」が欲しいという場合は「201個」を確保しておいて、使うときに常に「番号+100」しておけばよいでしょう。
さらに、最初に一括で値を代入してしまいます(注:一括代入ができる場合は限られる)。
その後、x[7]だけ、別に値を代入して値を変えてしまっています。
point には、double で、x,y,z という変数を含みます。
main()では、このpoint形式の変数 p を、3個セットの配列として作っています。
つまり、変数pは、p[0], p[1], p[2]各々にx,y,zが入った状態になっています。
このプログラムでは、ただ値を表示しているだけですが、もちろん式の中で使ったり、代入などもできます。
たとえば、構造体「三角形」{頂点1,頂点2,頂点3}のようになります。この場合、「.」で順次「中身」を触ることができます。
表計算については、この上で学ぶべきは「どんな関数があるか」だと考えます。 実際にやりたい作業を表現する関数を知らなければ、その作業ができないか、大幅に効率が悪くなります。これは、体験あるのみでしょう。
C言語については、
この講義で、「コンピュータに計算させること」に興味を持ったならば、2年生以降のコンピュータ演習系科目を受講するなり、C言語の参考書を一冊全部試してみるなり(多くの参考書のプログラムは、この講義での方法で、演習室では試せるはず)、実際に「やってみる」のがいいと思います。