for文, while文, 関数を理解しよう
for文とwhile文
何らかの命令を繰り返し実行させるプログラムを書くときに利用されるのが,for文 と while文 です.
それぞれ,(どのようなプログラミング言語でも概ね)次のような構文となります(C言語についてはすぐに説明します).
for i = 1,...,n
命令 i
これは,「i が 1 から n まで繰り返して 命令i を実行」というプログラムです.
while (条件)
命令
これは,「条件 が満たされている限り 命令 を実行し続ける」というプログラムです.
では,for文のサンプルプログラムをみてみましょう.
順番にみていきましょう.
まず,int i, n, x;
で,整数型の変数を3つ準備しています.少し下の for文 の中で使われている i についても型を宣言していることに注意してください.
次の,n = 10;
と x = 0;
は n と x の値の初期化です.
そして,for 文のところを見ていきましょう.for (i=1; i<=n; i++)
の括弧の中は,「i が 1 から n まで」という意味です.いま,直前で n に 10 を代入していますから,実際には「i が 1 から 10 まで」ということになります.なお,括弧の中のこの書き方はC言語特有です.例えば,来週から扱うJulia言語では for i = 1:n
といった書き方になります.そして,for (...)
に続く {...}
のところに命令が 書かれています.すなわち,x = x + i
が命令です.これをみて,「i は 0?」と思うかもしれませんが,これは方程式ではなく,「いまの x に i を足したものを新しく x の値とする」という意味です.このような書き方はほぼ全てのプログラミング言語で共通ですので,(特に数学科の学生にとっては)しばらくは違和感を覚えるかもしれませんが,慣れていってください.なお,x += i
は x = x + i
と同じです.
今回のプログラムでは,命令がどのように実行されるかみてみましょう.まず,for文 が始まる時点で x = 0 です.i=1のとき,x + i は 1 ですから,命令 x = x + i
が実行された結果,x の値は更新され,x=1 となります.次に,i=2 のとき,x + i は1 + 2 で 3 ですから,命令 x = x + i
が実行された結果,x の値は更新され,x=3 となります.次に,i=3 のとき,x + i は3 + 3 で 6 ですから,命令 x = x + i
が実行された結果,x の値は更新され,x=6 となります.もう分かりましたよね?以上の操作を i = n まで繰り返すわけですから,i = n のときの命令が実行された結果,x の値は 1からn までの整数の和になっているはずです.このプログラムでは n=10 ですから,x = 55 になっているはずです.for文 に続くprintf("x=%d\n",x);
は,x の値の出力ですから,このプログラムをコンパイルして実行すると.x=55
という結果になります.
では今度は while 文のサンプルをみてみましょう.
while文 の中をみてみましょう.まず最初は,a = 1 ですから,n = n + a
と a = a + 1
がそれぞれ実行され,n = 1, a = 2 となります.その直後の if文 は,もしa = 10 ならば while文 を抜け出すという命令です.いま,a = 2 ですから該当しません.そこでもう一度 while 文 の先頭に戻ります.a = 2 ですから a < 100 という条件は満たしていますので,さきほどと同様に,n = n + a
と a = a + 1
がそれぞれ実行され,n = 3, a = 3 となります.この操作を a = 10 になるまで繰り返すわけです.従って,while 文 を抜け出すときには,n は 1 から 9 までの整数の和になっているはずです.このプログラムをコンパイルして実行すると.n=45
という結果になります.
関数
これまでみてきたプログラムはいずれも数行程度の簡単なものでしたが,一つのプログラムの中で何度も同じような計算をするときに,一から for文 や while文 を使って書くのは大変ですし,バグの原因にもなります(うっかりミスが増えます).例えば,1 から n までの自然数の総和を計算するときには,sum(n)
という感じで書くことができれば,とても楽になりそうです.例えば,上記のfor文のプログラムを次のように書くことができれば,かなり可読性が高くなりそうです.言い換えれば,他人が読んでも,あるいは書いた本人が一ヶ月後に読んでも,どんなプログラムかすぐに分かりますよね.
ただし,これだけでは sum
が定義されていないので,その定義も書く必要があります.その定義も含めたプログラムは次のようになります.
では,int sum(int n){...}
の中をみていきましょう.まず,
int
sum
(
int n
)
の sum は関数の名前です.関数の名前は自由に決めればよいのですが,f とかだと,結局どんな関数なのか分かりづらいので,通常は,どういう関数なのかイメージしやすい名前をつけます.この関数は,整数 をもらって,整数 を返す関数です.この場合,整数 のことを 引数 と呼び,括弧の中には int n のように 型 + 変数名 を書きます.そして,整数 のことを 戻り値 といいます.int は戻り値の型が整数であることを示しています.
次に,{...}
の中についてですが,for文 が終わると x の値は 1 から n までの総和になっています(これは for文 のところで説明した通りです).そして,for文 に続く return x;
で x が出力であることを示しています.
ここで一つ注意です.int sum(int n){...}
では戻り値は int型 といっています.そして,{...}
の中で,x の型は int型 と宣言しています.この両者が一致していないと,コンパイルが通りません.
数学関数
三角関数といった標準的な数学関数は,#include <math.h>
を冒頭で宣言することで利用できます.一例をみてみましょう.
再帰関数
再帰関数 とは「関数の中で自分自身を呼び出す関数」のことです.例えば,\(f(n) = n!\) のように階乗を計算する関数を定義したいとき,もちろん for文 や while文 を使って定義することもできますが,\(f(n) = n \times f(n-1)\), \(f(0) = 1\) のように定義することもできます.
再帰関数は直感的な定義をそのままプログラムにすることができますが,場合によっては次のような問題があることに注意する必要があります.
- 関数を呼び出す回数が指数的に増えて,計算量が膨大になることがある.
- メモリの使用量が増える.
課題
フィボナッチ数列を求める/出力するプログラムを2通り(for文 を使うものと 再帰関数 を使うもの)作成してみよう.すなわち,以下のプログラムの /* 埋める */
の部分を埋めましょう(埋めたら /* */
は消してください).