[復習] 引数付き関数 関数作成 => 既存の命令に名前を付る 1. 名前を決める foobar 2. それを main 関数の外に書く foobar 3. その前と後ろに、void, (void) void foobar (void) 4. {} を追加 void foobar (void) { } 5. {} の中に、名前を付けたい、命令をかく void foobar (void) { printf ( "Hello, World\n" ); } => 1 から 5 を「関数定義」 <= この形式(引数なし)の関数 毎回、同じ操作(命令)しかできない 6. 呼び出す度に、異なるふるまいをさせたい => 実行するときに、命令の一部が「変化」 「変更」される、データの部分を、「変数」に変更する void foobar (void) { printf ( "Hello, " ); printf ( X ); 「X」という変数 printf ( "\n" ); } 7. 変数の値は、「引数」で指定する void foobar (char *X) { 引数で X の値を決める printf ( "Hello, " ); printf ( X ); 「X」という変数 printf ( "\n" ); } => 引数付き関数 => 関数呼び出しに、関数の引数に、 命令内の変数に入れる値を指定する事が可能になる 命令を実行するときに、変数の部分が、 引数で指定したものに変化する => 引数を追加する事により、関数の「汎用性」が増した 「汎用性」:それが、どの範囲で利用できるかの指標 汎用性が高い => 利用できる範囲が広くなる make make と Makefile Makefile : 何かの作業の手順が記述されている ! 一種のプログラム(だが、C 言語などとは、動作原理) make コマンドにより Makefile が読み取られ、 作業が、「自動的おこなれる」 => プログラム開発の作業が自動化される [ポイント] [基本] Makefile があったら、make する [応用] make の後ろにマクロ定義可能で、これによって、 自分のプログラムの自動化が可能になる 課題として、「Makefile を作る」 分割コンパイル 一つのプログラムを、複数のソースコード(*.c)の中に記述して、 個々にコンパイルする事 cf. (最初は..) 一つのソースコードに、プログラムの内容をすべて 記述する(例 : helloworld.c) コンパイルは、このファイル一個 => オブジェクトファイル(*.o)が一つできる リンク時も、そのオブジェクトファイル一個を指定して、 実行ファイル (*.exe) を作成 プログラム = *.c => *.o => *.exe (分割コンパイル) プログラム = 1.c, 2.c, .., k.c ( k 個に分割 ) => 1.o, 2.o, ..., k.o ( k 個のオブジェクトファイル) => k 個のすべてのオブジェクトを一つ実行にファイルにリンクする => 実行ファイルは一つ [欠点] 作業量が増える <= make を作った [利点] ソースコードを分けた => 個々の関数(ここのソースファイルで定義されている)が 互いに、独立に利用できる cf. 事例 p1 => main(固有), sub1, sub2, sub3 p2 => main(固有), sub2, sub3, sub4 sub2, sub3 は同じものでよい ここで、もし、分割しないと p1.c の中に main, sub1, sub2, sub3 p2.c の中に main, sub2, sub3, sub4 二つの .c の中に sub2, sub3 が同時にあられる => 一方に、他方を Copy する事になる => 原理的に「バグ(プログラムの誤り)」の増殖につながる 一方、分割コンパイルの場合 p1.c => main sub1.c => sub1 sub2.c => sub2 sub3.c => sub3 p2.c => main (sub2.c => sub2) (sub3.c => sub3) # p1 の時のものをそのまま利用 sub4.c => sub4 # => sub2 の記述は一か所にしかない # => 万が一、sub2 にバグがあっても # 修正は、一か所で済む(事が保証される) [今日の話] 引数付き関数 => 関数の振る舞いを引数の値によって、変化させられる => 振る舞いの変化は、引数の変化に同調している(連続的) 変更の対象が、データだけで、命令そのものは変化していない 変数で変わったは、命令の対象が変わった <= 振る舞いそのものを変えたい 例: 出力の回数を変化させたい (今回の例では、必ず 3 回 => 場合によって 1 回とか 2 回にしたい) => 条件分岐 条件分岐 条件分岐とは(what) 条件によって、複数の命令のどちらか一方を実行する機構 C 言語で、条件分岐をするには(How To) 「if 構文」を利用する 複数の命令(A,B)を組み合わせる方法 1. 順接 (プログラムの記述量と実行する量が同じ) A B => A をやってから B を行う 2. 条件分岐(プログラムの記述量に比べ実行する量が少ない) if ( .. ) { A } else { B } => A, B のどちらか一方 => 1, 2 の組み合わせだけで記述されたプログラムは、 そのプログラムの長さ以下の実行しかしない 3. 繰り返し(同じ命令を何度も実行する仕組み) => 1 度しか書いていない命令が、何度も実行される可能性がある 文字列について C 言語では、「文字列に 1 を加える」と、文字列の先頭が失われて、 文字列の長さが、その一文字分短くなる 再帰呼び出し利用して、関数を定義すると、 その関数の命令の一部(再帰呼び出しをしていない部分)が、繰り返される。 [数学] 階乗 : 5! = 5 * 4 * 3 * 2 * 1 = 120 1 (n=0 の時) n! = { n * ((n-1)!) (その他) # 帰納的定義 => これの性質は数学的帰納法で示す事ができる 漸化式 数列 { a_n } が初項 a_0 で、公差が d の等差数列とする a_n = a_0 + (n-1) d 漸化式 a_0 (n=0) a_n = { a_{n-1} + d (その他 ! 「数学」では当たり前のように、帰納的定義がなされている ! C 言語では、それが、再起呼び出しになっている