[先週] Hanoi の課題 再帰的定義の「繰り返し」以外の利用例 「繰り返し」の場合は、基本、再帰的な呼び出しは一回で行う <= Hanoi の場合は、再帰呼び出しが二回ある # 再帰の方は、繰り返し実現しようとすると大変なものを、 # 単純に表現できる(事がある)点が繰り返しより有利 関数の整数引数 => 引数宣言の重要性 「引数宣言」:関数の引数に、どのような型(int.char *)が指定できるか ? を表す宣言 これは、「型チェック」に利用される 「型チェック」:実際に関数呼び出しを行うときに、その引数の型が、 引数の型宣言の型と一致しているかどうか確認する事 => 「型チェックに引っかかる(型が違う)」場合は、誤りである可能性が(非常に..)高い <= 人間は「誤りを犯す」生き物 => 誰かが、「誤りのチェック」を行ってやる必要がある <= この仕事の一部をコンパイラが肩代わりしてくれている => この仕事をするために、「照らし合わせる」情報 => 関数の引数宣言 これが分割コンパイルに及ぼす影響 関数の定義(関数引数の宣言を含む)と関数呼び出しが一つのファイル内にある => コンパイラが、型チェックを行う事ができる 分割コンパイルすると、引数の型宣言と、関数呼び出しが別々なので、チェックできない => プロトタイプ宣言(関数の引数宣言を含む)をヘッダーファイルに記述し、 このファイルを、関数定義と、関数呼び出しの双方で参照(include)する事により、 分割コンパイルでも、型チェックが適切に働くようにする必要がある #include その場所に、指定したファイルを読み込みなさいという指示 形式は二種類 <> と "" の二つ cf. #include 毎回 #include "p-001.h" 前回 <> は、stdio.h のファイルの置き場所が固定されていて、そこのものが利用される /usr/include にある => 標準的に提供されていて(どのシステムでも存在する事が保証されている)もの => 無条件に利用可能 (標準関数 [cf. printf] と同じ) "" は、プログラマが自分で作成する 基本は、.c と同じところに置く 応用は、-I で指定したディレクトリに置いてあればよい [本日の内容] <作業> c:\usr\c\include の中身を確認する 2019/06/28 のページから次の二つのファイルを c:\usr\c\include に保存 s_print.h, s_input.h の使い方 1. #include で読み込む 2. s_print_XXX (XXX = string, int, char) でそれぞれの型のデータを出力 cf. p-003.c 3. コンパイル時に「-I ~/c/include」を指定する の使い方 基本 s_print.h と同じ / s_input_XXX でデータの入力が可能 cf. p-004.c [入力] 「入力」:プログラムが実行されるとき(実行中)に、情報を(プログラムの外から)与えられる事 !! 「実行時」の概念で、「コンパイル時(プログラム時)」では無い !! => あらかじめ知る事ができない(実行時の入力データは、プログラム時には予想できない..) !!!! => 場合によっては、「変な事が起きる」かもしれない !!!! <= それに対して対応(準備)が必要(エラーチェック..) C 言語では、「入力」は、「入力関数」を呼び出すと、その時点(プログラムの実行 時に、その関数が呼び出される時点)で、行う事が可能になり、 (キーボードなどの入力元から)データが入力された時点で、関数の値として 取り出せるようになる 例: getchar() : 文字を一文字、入力する関数 => 標準ライブラリ 例2: s_input.h を利用する事により(講義独自なので、外では使えない..) s_input_char() s_input_int() s_input_string() 等が利用できる プログラミング プログラムの基本設計構造一つ (Input-process-output) 情報を入力し、その情報を加工して、その結果を出力する 入力関数は、呼び出された時点で「入力」を行い、その結果を返す。 呼び出されるたびに、「入力」が行われ、毎回、その入力結果(入力情報)が返る => 入力関数の値は、呼び出す度に異なる その(同じ)値を一度しか利用なら、あまり問題がないが、 複数回利用したい場合は、面倒。 => 入力したい値を複数回利用したい場合は、他の関数の引数に指定して、 その指定した関数で、引数変数を複数参照する 入力関数は、「入力する」という副作用があるので、 入力関数を含む「式」は、数学的な式とは異なる振る舞いをする cf. f() + f() != 2 * f() とならない # f() が副作用をもたない純粋関数なら、問題ない !! 同じ「入力値」を複数回参照したい場合 !! その入力値を入力するための入力関数を、関数の引数に指定して、 !! 関数内で、その値を引数変数経由で、(副作用無しに)何度でも参照する事ができる 条件分岐のバリエーション 条件分岐 : if 構文で行う if ( 条件 ) { 条件が成立した時 } else { 条件が不成立の時 } => 分岐が二つの場合しか考えていない <= if 構文を組み合わせる事より、多数の場合分けは可能 例 : 整数値を、正、ゼロ、負の三つにわける場合 if ( num > 0 ) { printf ( "正\n" ); } else { if ( num < 0 ) { printf ( "負\n" ); } else { printf ( "ゼロ\n" ); } } => if 構文一つ覚えれば、その組み合わせで、任意の場合分けができる [else if] if ( num > 0 ) { printf ( "正\n" ); } else if ( num < 0 ) { /* else if : 一組 {} を削除 */ printf ( "負\n" ); } else { printf ( "ゼロ\n" ); } [例] 整数値が 4 で割ってあまりが 0, 1, 2, 3 の場合 if ( num % 4 == 0 ) { printf ( "あまりは 0\n" ); } else if ( num % 4 == 1 ) { printf ( "あまりは 1\n" ); } else if ( num % 4 == 2 ) { /* 場合分けが増えると else if 一つ増える */ printf ( "あまりは 2\n" ); } else { printf ( "あまりは 3\n" ); } [返(かえ)り値を持つ関数] return 命令 それを実行する事によって関数の処理を終了すると同時に、 return の後ろにある式の値が、関数の値として返す機能を持つ