/* * 20210618-02-QQQQ.c * 二つの整数値を入力して、その余りを出力する * input-process-output * input -> s_input_int * process -> % * output -> s_print_int */ #include <stdio.h> #include "s_print.h" /* s_print_int を利用する(整数値の入力の)ため */ #include "s_input.h" /* s_input_int を利用する(整数値の出力の)ため */ /* * remainder * 「%」演算子(整数同士の余りを計算する) を使って、「余り」の計算をする */ int remainder ( int a ) { /* 引数変数 a には、割られる数が入っている.. */ /* 余りを計算するために、割る数を入力する必要がある */ s_print_string ( "割る整数を入力して、[Enter] を押してください : " ); return a % s_input_int(); } /* * main */ int main ( void ) { s_print_string ( "割られる整数を入力して、[Enter] を押してください : " ); s_print_int ( remainder ( s_input_int() ) ); /* 割られる数を入力する */ s_print_newline(); return 0; }
#include <stdio.h> int main(void) { printf ( "Hello, World\n" ); return 0; }
#include <stdio.h> int main(void) { putchar( getchar() ); /* getchar() によって、キーボードから 文字一文字入力する */ /* getchar() が返す文字(コード)を putchar を使って、出力する */ /* 5 行目の命令によって、「何が起きるか ?」 は、 プログラムを実行した時に、キーボードから何を 入力するかによって、決まるため、 プログラム作成時には、予測ができない */ putchar( '\n' ); /* 改行が表示される */ return 0; }
#include <stdio.h> char process ( char ch ) { return ch + 1; /* ch の次の文字 */ } int main(void) { putchar ( process ( getchar() ) ); putchar ( '\n' ); return 0; }
#include <stdio.h> #include "s_print.h" #include "s_input.h" int main(void) { /* string */ printf ( "文字列を入力して、それを出力する : " ); s_print_string ( s_input_string() ); printf ( "\n" ); /* int */ printf ( "整数値を入力して、それを出力する : " ); s_print_int ( s_input_int() ); printf ( "\n" ); return 0; }
#include <stdio.h> #include "s_print.h" #include "s_input.h" int main(void) { /* string */ printf ( "文字列を入力して、それに +1 したものを出力する : " ); s_print_string ( s_input_string() + 1 ); /* 「文字列」に + 1 なので、先頭の文字が欠けて、短くなる */ printf ( "\n" ); /* int */ printf ( "整数値を入力して、それ +1 したものを出力する : " ); s_print_int ( s_input_int() + 1 ); /* 「整数値」に + 1 なので、1 だけ増える */ printf ( "\n" ); return 0; }
#include <stdio.h> /* numplus 数字の時だけ、+1 する ch が数字 '0' <= ch <= '9' 「'0' <= ch」 と 「ch <= '9'」の両方 */ char numplus ( char ch ) { /* 文字(コード)を返すので、 関数の値の型を char としている */ if ( '0' <= ch ) { if ( ch <= '9') { /* 条件 「'0' <= ch <= '9'」が成立した時 */ return ch + 1; /* ch で与えられた「文字」の次の「文字」 */ /* return 命令を使って、関数の返す値を指定している */ } else { return ch; /* もとのまま */ } } else { return ch; /* もとのまま */ } } int main(void) { printf ( "文字を入力してください : " ); putchar ( numplus ( getchar() ) ); putchar ( '\n' ); return 0; }
#include <stdio.h> int main(void) { return 99; /* プログラムの終了時に、 プログラムの実行結果のステータス(状況) をプログラムの呼び出し元(シェル)に返す その値は(シェルでは)「$?」で参照できる */ /* より一般には、プログラムのエラーコードを main の return 文で示す事が多く、 0 は、異常無し ( 正常終了 ) それ以外は、エラー(異常終了)で、 その値(0 以外の値)はエラーコード(エラーの種類)を示す */ }
#include <stdio.h> #include <stdlib.h> /* exit 関数を利用する場合 */ void sub(void) { printf ( "Sub : 関数が呼び出された 1\n" ); exit( 99 ); /* exit 関数の呼び出し */ /* => ここで、プログラムが終了し、 実行ステータスが 99 になる */ printf ( "Sub : 関数が呼び出された 2\n" ); } int main(void) { printf ( "Main : 関数を呼び出す前\n" ); sub(); printf ( "Main : 関数を呼び出す後\n" ); return 0; /* 正常終了 */ }
#include <stdio.h> #include <limits.h> #include "s_print.h" int main(void) { s_print_string ( "INT_MAX = " ); s_print_int ( INT_MAX ); s_print_newline(); s_print_string ( "INT_MIN = " ); s_print_int ( INT_MIN ); s_print_newline(); return 0; }
#include <stdio.h> #include "s_print.h" int main(void) { s_print_string ( "123 + 456 = " ); s_print_int ( 123 + 456 ); /* 「+」で和の計算 */ s_print_newline(); s_print_string ( "123 - 456 = " ); s_print_int ( 123 - 456 ); /* 「-」で差の計算 */ s_print_newline(); s_print_string ( "123 * 456 = " ); s_print_int ( 123 * 456 ); /* 「*」で積の計算 */ s_print_newline(); return 0; }
#include <stdio.h> #include "s_print.h" /* f(x) = x^2 = x * x */ int f(int x) { s_print_string ( "関数 f が呼ばれました\n" ); return x * x; } /* g(x) = x + 3 */ int g(int x) { s_print_string ( "関数 g が呼ばれました\n" ); return x + 3; } int main(void) { s_print_string ( "f(g(5))=" ); s_print_int ( f(g(5)) ); s_print_newline(); return 0; }
#include <stdio.h> #include "s_print.h" /* f(x) = x^2 = x * x */ int f(int x) { s_print_string ( "関数 f が呼ばれました\n" ); return x * x; } /* g(x) = x + 3 */ int g(int x) { s_print_string ( "関数 g が呼ばれました\n" ); return x + 3; } int h(int x, int y) { s_print_string ( "関数 h が呼ばれました\n" ); return x % y; } int main(void) { s_print_string ( "h(f(3),g(5))=" ); s_print_int ( h(f(3),g(5)) ); /* f と g ではどちらがよばれるか */ s_print_newline(); return 0; }
#include <stdio.h> #include "s_print.h" #include "s_input.h" int div( int x, int y ) { return x / y; } int main(void) { s_print_string ( "二つの整数値を入力して、その商を計算する\n" ); /* キーボードから 12, 4 と入力する .. */ s_print_int ( div( s_input_int(), s_input_int() ) ); /* 4 */ /* 12 */ /* => 4 / 12 = 0 */ s_print_newline(); return 0; }
#include <stdio.h> void sub( int n ) { if ( n > 0 ) { printf ( "n は非負の整数\n" ); } else { /* ここではなにもしない */ } } int main(void) { printf ( "sub(10)\n" ); sub(10); printf ( "sub(-10)\n" ); sub(-10); return 0; }
#include <stdio.h> void sub( int n ) { if ( n > 0 ) { printf ( "n は非負の整数\n" ); } /* 条件が不成立の時の命令が空っぽの場合は、else 節を省略できる */ /* 「else {}」は書くだけ無駄 */ } int main(void) { printf ( "sub(10)\n" ); sub(10); printf ( "sub(-10)\n" ); sub(-10); return 0; }
#include <stdio.h> #include "s_input.h" #include "s_print.h" /* トランプの番号 1 ? 13 を入力し、その記号 1 => A 2 ? 10 => 2 ? 10 11 => J 12 => Q 13 => K その他 => ? */ void sub( int num ) { if ( num == 1 ) { printf ( "A\n" ); } else if ( num == 11 ) { printf ( "J\n" ); } else if ( num == 12 ) { printf ( "Q\n" ); } else if ( num == 13 ) { printf ( "K\n" ); } else { if ( 2 <= num ) { if ( num <= 10 ) { s_print_int ( num ); s_print_newline(); } else { printf ( "?\n" ); } } else { printf ( "?\n" ); } } } int main(void) { printf ( "トランプの番号を入力して、記号を出力する\n" ); sub ( s_input_int() ); return 0; }
前回(2021/06/18)の内容 講義内容 入力 プログラムの実行時に、 外から、プログラムに対して、データ与える 出力(入力の逆) プログラムから外にデータを出す 入力はプログラム実行時に初めて与えられる プログラム作成時には、わからない より、プログラムの動作に対する予測が難しくなる => プログラムの誤りに気づきにくくなる (入力によって、異なる振る舞いをするので..) 一つのプログラムで(実行時に異なる入力を行う事により..) 複数の事ができるようになる cf. 引数付き関数 引数無し関数は、毎回同じ振る舞い 引数付き関数は、引数によって、異なる振る舞いをする 入力のないプログラム 処理するためのデータが、あらかじめ、プログラム内に記述されている 動作に関して、予想が可能 (一般には..) 毎回同じ振る舞いをする 扱いやすさ 汎用性 入力無し 簡単 単機能 入力有り 難しい 多機能 引数無し関数 簡単 単機能 引数付き関数 難しい 多機能 「入力-処理-出力」 プログラムの基本パターン データを「入力」し それを「処理」した後に、 その処理結果を「出力」する main 関数で、入力と出力を行う 処理の部分を値を返す関数で任せる 入力 / 出力 : プログラムの外とやり取り <= main に「外とのやり取り」を集める プログラムの設計が分かりやすくなる => main 以外の関数は、 引数で、データを入手し、(関数への入力) 関数の値で、データを返す(関数からの出力) <= Program の中で閉じる s_print.h/s_input.h の使い方 1. プログラムソースファイル内(*.c)の先頭の部分に !! #include <stdio.h> の下位所 次の二行をいれる #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 } 入れ子による、段の深化が防げる 一つのデータに対して、複数の条件の検査になっている 「表現」と「意味」の対応 (イデオム)
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20210625-01.c
/* * 課題 CNAME-01 * * CDATE FILENAME * * キーボードから一文字入力し、その文字によって異る国の挨拶をする */ #include <stdio.h> /* * hello ( char contry ) * char contry : 国を表す一文字 * j : 日本 * e : 英語 * c : 中国 * f : フランス語 * g : ドイツ語 */ void hello ( char cmd ) { switch ( cmd ) { case 'j': /* 'j' の時は、日本語にする */ printf ( "こんにちは\n" ); break; case 'e': /* 'e' の時は、英語にする */ /* ** この部分を完成させなさい */ break; case 'c': /* 'c' の時は、中国語にする */ printf ( "ニイハオ\n" ); /* ** この部分を完成させなさい */ case 'f': /* 'f' の時は、フランス語にする */ printf ( "Bonjour\n" ); break; /* ** この部分を完成させなさい */ printf ( "Guten tag\n" ); break; default: /* どれでもなければ.. */ printf ( "???\n" ); break; } } /* * main */ int main( void ) { printf ( "国を表す文字を入力してください\n" ); printf ( "\tj\t日本\n" ); printf ( "\te\t英語\n" ); printf ( "\tc\t中国\n" ); printf ( "\tf\tフランス\n" ); printf ( "\tg\tドイツ\n" ); hello ( getchar() ); /* getchar() で文字を入力し、それに対応する結果を出す */ return 0; }
f
$ ./20210625-01-QQQQ.exe 国を表す文字を入力してください j 日本 e 英語 c 中国 f フランス g ドイツ Bonjour $
Download : 20210625-02.c
/* * 20200710-02-QQQQ.c * 三つの整数値の内、真ん中の数値を返す関数 */ #include <stdio.h> #include "s_input.h" #include "s_print.h" /* * middle * 引数で指定された三つの数値の内、真ん中の数値を返す関数 */ int middle ( int a, int b, int c ) { if ( a >= b ) { if ( b >= c ) { /* a >= b >= c となるので、真ん中の数値は b */ return b; } else if ( a >= c ) { /* a >= c > b となるので、真ん中の数値は c */ /* ** この部分を完成させなさい */ } else { /* c > a > b となるので、真ん中の数値は a */ return a; } } else if ( c >= b ) { /* c >= b > a となるので、真ん中の数値は b */ return b; /* ** この部分を完成させなさい */ } else { /* b > c > a となるので、真ん中の数値は c */ return c; } } /* * main */ int main ( void ) { s_print_string ( "キーボードから三つの整数値を入力すると、真ん中の数値を表示します\n" ); s_print_int ( middle ( s_input_int(), s_input_int(), s_input_int() ) ); s_print_newline(); return 0; }
10 30 20
$ ./20210625-02-QQQQ.exe キーボードから三つの整数値を入力すると、真ん中の数値を表示します 10 30 20 20 $