前回(2021/06/18)の内容 講義内容 入力 プログラムの実行時に、 外から、プログラムに対して、データ与える 出力(入力の逆) プログラムから外にデータを出す 入力はプログラム実行時に初めて与えられる プログラム作成時には、わからない より、プログラムの動作に対する予測が難しくなる => プログラムの誤りに気づきにくくなる (入力によって、異なる振る舞いをするので..) 一つのプログラムで(実行時に異なる入力を行う事により..) 複数の事ができるようになる cf. 引数付き関数 引数無し関数は、毎回同じ振る舞い 引数付き関数は、引数によって、異なる振る舞いをする 入力のないプログラム 処理するためのデータが、あらかじめ、プログラム内に記述されている 動作に関して、予想が可能 (一般には..) 毎回同じ振る舞いをする 扱いやすさ 汎用性 入力無し 簡単 単機能 入力有り 難しい 多機能 引数無し関数 簡単 単機能 引数付き関数 難しい 多機能 「入力-処理-出力」 プログラムの基本パターン データを「入力」し それを「処理」した後に、 その処理結果を「出力」する main 関数で、入力と出力を行う 処理の部分を値を返す関数で任せる 入力 / 出力 : プログラムの外とやり取り <= main に「外とのやり取り」を集める プログラムの設計が分かりやすくなる => main 以外の関数は、 引数で、データを入手し、(関数への入力) 関数の値で、データを返す(関数からの出力) <= Program の中で閉じる s_print.h/s_input.h の使い方 1. プログラムソースファイル内(*.c)の先頭の部分に !! #include の下位所 次の二行をいれる #include "s_print.h" /* 出力用 */ #include "s_input.h" /* 入力用 */ 2. コンパイル時に -c オプションの前に、 -I ~/c/include を挿入する 3. プログラム中で s_print_QQQQ s_input_QQQQ QQQQ のところには、 string 文字列 char 文字 int 整数値 newline 改行 (出力の時だけ..) 4. 注意 s_ は、この講義専用の関数 ( 一時的な利用 ) => 講義以外では使わないようにする 返値(かえりち)のある関数 (1) 関数に返り値を与える事ができる cf. 数学の関数の場合は、「関数値」があるのが当然 例: f(x) = x^2 f(3) = 3^2 = 3 * 3 = 9 関数適用 「f(3)」の(関数)値は、「9」になる C 言語の場合 関数の値は考えていない 関数に対し、関数の値を定義できるようになった 表現方法 1. 関数宣言の頭部の(関数名の前に書く) void を、 関数が返す値の型名にする 文字を返すならば、char にする 文字列を返すならば、char * にする 2. 関数の本体の中に、 return 式; 命令を書き、関数の返す値として、「式」の結果を指定する !! 値を返す場合は、どんな場合でも、 !! 「return 式」が実行されるようにする !! どの場合でも式の結果は、返す値の型にする必要がある [2021/06/25] 関数の値 関数の返値(かえりち)[戻り値] 関数は return 命令を利用する事により、値を返す事ができる 値を返す場合は、関数名の前の void の代りに返す値の「型名」を記述 「void (空虚/無)」=> 「関数の返り値が『無い』」事を表現 cf. 仮引数変数が『無い』場合も「void」としていた.. return 命令 return 命令の後ろに「式」を書くと、その「式の値」が関数の返値になる return 命令が実行されると、その関数の実行は終了する(以下の命令は実行されない) void 関数(値を返さない関数)でも、式を省略した return が書ける return 命令は、制御構造の一つ !! 「制御構造」命令の実行の順序に影響を与える命令 値を返す関数は、 関数の最後に必ず return 命令を書く習慣を付ける return 命令を必ず実行するようにする main 関数の返値 整数の値を「終了ステータス」として返す習慣がある 「0」 は、「正常終了」を意味する 「0 以外の値」は、「異常終了(値はエラーコード)」を意味する exit 関数を利用して、main 以外でも、終了(終了ステータスの指定)ができる main 関数の返値の利用例 shell 変数「$?」で、参照可能 例 : cc (C コンパイラ) コマンドは、コンパイルエラーを見付けるとエラーコードを返す 整数型 C 言語で扱えるデータの種類(型) !! データは、型が異なると、 !! 扱いが変わる !! 表現方法 !! できる計算(入力、出力方法)が違う !! 同じ事ができても、結果異なる 文字列 : 「"」で挟まれた「文字の列」 例: "abc", "123", "9" 型名: char * 文字 : 「'」で挟まれた「文字」 例: 'a', '1', '9' 型名: char 整数 : (符号)数字並び 例 : 123, 9 型名: int 整数型 C 言語でも整数(の一部)が扱える 整数型 : -2^31 〜 2^31 - 1 (2147483647) まで範囲の整数 (cf. limits.h) 整数の計算 四則 ( 和: +, 差: -, 積: *, 商: /, 余り: % ) の計算ができる 整数の比較 ( if 構文の条件部で利用する ) cf. 「文字」と同じ ( 「文字」は 1 byte の整数値 ) 等価 ( 等しい: ==, 等しくない: != ) 大小比較 ( 大なり: >, 小さいなり: <, 以下: <=, 以上: >= ) 整数の入出力 s_print_int()/s_input_int() を利用する ※ 他にも色々できるのだが、しばらくは触れない 整数型の宣言 ( 引数/返り値 ) 「int」を利用する ( 以前は char * [文字列] / char [文字] だった ) 関数合成 順接: 命令を順番に並べると、その順に実行する f(); g(); h(); => f, g, h の順に実行する 関数合成: 関数の内側から外側に向けて実行される(cf. 数学) f(g(h())) => h, g, f ! 関数の評価 ( 関数適用を呼び出して、値を計算する ) ! 内側から外側の順でも外側から内側でも同じ結果になる ! 例 ! f(x) = x^2 = x * x ! g(x) = x + 3 ! f(g(5)) ! [内側から外側] ! f(g(5)) ! => f(5 + 3) ! => f(8) ! => 8*8 ! => 64 ! [外側から内側] ! f(g(5)) ! => g(5)*g(5) ! => (5+3)*(5+3) ! => 8*8 ! => 64 条件分岐 (if 構文) !! 制御構造 : 命令を組み合わせて、新しい命令を作る仕組み !! => 命令の実行する順序を制御する !! 順接は、「何も制御しない(順序を変えない)」 !! return 命令は、「関数を強制的に終了させる」 条件分岐 複数の命令の内、条件によって、いずれか一つを実行する仕組み 与えれた状況に併せて、適切な対応を選択する仕組み !! 「状況」: 条件式に含まれる、変数や関数の値 !! 「適切な対応」: 実行する命令 プログラムの柔軟性を高める仕組み !! 条件分岐が無いと、実行される命令列が確定する !! 命令列が確定しても、命令に含まれる変数の値が異なれば、 !! 異なる振る舞いをする !! 条件分岐が無いと、実行する命令の種類や数が変化しない if 構文 : 条件分岐を実現する C 言語での表現方法 構文 : if ( 「条件」) { 「条件の成立時の文」 } else { 「条件が不成立時の文」 } 条件 : 真偽値(成立/不成立)を求める式 条件の成立時の文 / 条件が不成立時の文 : 複数の文(命令)が指定できる 意味: 「条件」が『成立』した時に 「条件の成立時の文」を、 そうでない時には、 「条件が不成立時の文」を 実行する どちらか一方だけが実行される ( 両方実行も両方不実行もなし ) 「if 『文』」ではなく、「if 『構文』」である理由 「『文』を対象として、『何かをする表現』」なので「メタ表現」 if 構文 アラカルト !! 色々な if 構文の表現 if 構文の基本 : if ( C ) { A } else { B } !! 基本方針(ソフトウェア概論「流」) !! 必ず「{,}」を書く !! 必ず「else」を書く !! <= 本当は、必須ではないのにも関わらず.. 「基本」は「基本の組み合せだけで何でもできる」の秀逸 !! 色々な表現方法 !! => ある目的に特化している !! (「特化」しているので..)利点(表現が楽)がある同時に、決定(できない事)が生じる 色々な組み合せ方を学ぶ必要がある else 節の省略 else 節 : if 構文の 「else { B }」の部分 B が空の時は、「else {}」としても良いが、 それを省略しても良い (「 if ( C ) { A } else { } 」==「 if ( C ) { A } /* 省略可能 */ 」) then 節 ( { A } の所 ) は省略できない (「 if ( C ) { } else { B } 」は「 if ( C ) else { B }」 とはできない) if 構文の「入れ子」 if 構文の文の中に if 構文をいれる !! (内側の..)if 構文によって、新しい文(命令)が作られる !! => 外側の if 構文からみれば、 !! 内側の if 構文は、単なる命令なので、 !! if 構文が入れ子になっているかどうかは、 !! 外側の if 構文の観点からは、区別する必要がない 複数の条件の「条件の組み合せ」を if 構文の組み合せ(入れ子)で実現できる 例 : 変数 ch に入っている文字が「英大文字かどうか」を判定したい => 複合条件 : 'A' <= ch <= 'Z' => 二つの条件「'A' <= ch」と「ch <= 'Z'」の両方が 「同時に成立」している事を意味する if ( 'A' <= ch ) { if ( ch <= 'Z' ) { /* ch が大文字の時 */ } else {} } else {} => どちらか一方の場合は、 if 構文を順接でつなげる P と Q の一方が成立している if ( P ) { } else {} if ( Q ) { } else {} else if 構文 (イデオム) else 節の命令(条件が不成立の時の命令)が、 単独の if 構文からなる場合 => else 節の命令文を囲む {, } を省略する if ( ) { } else { if ( ) { } else { } } => if ( ) { } else if ( ) { } else { } else 節の文全体が if 構文(入れ子)になっている場合 else 節のブレースを省略する 例: if ( C1 ) { A } else { if ( C2 ) { B } else { C } } => if ( C1 ) { A } else if ( C2 ) { B } else { C } 入れ子による、段の深化が防げる 一つのデータに対して、複数の条件の検査になっている 「表現」と「意味」の対応 (イデオム)