/* * 20200710-02-QQQQ.c * 入力された文字の字種を答える関数 */ #include <stdio.h> /* * print_chractor_type ( char ch ) * 引数で指定された文字の種類 ( 大英文字、小英文字、数字、その他 ) * を判定し、その種類を表示する */ void print_chractor_type ( char ch ) { /* まず、英大文字 ( 'A' <= ch <= 'Z' ) かどうかを判定 */ /* => これは二つの条件「'A' <= ch」と「ch <= 'Z'」の双方をチェック */ if ( 'A' <= ch ) { /* 'A' 以上で.. */ if ( ch <= 'Z' ) { /* 'Z' 以下なので.. */ /* 二つの条件「'A' <= ch」と「ch <= 'Z'」の双方が成立 */ putchar ( ch ); printf ( " は、英大文字です。\n" ); return; /* ここで関数を終了 ( 返り値はない ) */ } /* else {} */ /* else 節は省略 */ } /* else {} */ /* else 節は省略 */ /* まず、次は英小大かどうかを判定 */ if ( 'a' <= ch ) { if ( ch <= 'z' ) { /* .. */ return ; } } /* 最後に、数字かどうかを判定 */ if ( '0' <= ch ) { if ( ch <= '9' ) { putchar ( ch ); printf ( " は、数字です。\n" ); return; } } /* ここまで何かの条件が成立すれば return で終了している筈 */ /* ここにきたという事は、どの条件も成立していないので、「その他」と判定して良い */ putchar ( ch ); printf ( " は、その他です。\n" ); return; /* この return は不要だが、省略しない方が良い */ } /* * main */ int main ( void ) { printf ( "キーボードから一文字入力すれば、文字の種類を表示します : " ); print_chractor_type ( getchar() ); return 0; }
#include <stdio.h> #include "s_print.h" #include "s_input.h" int main(void) { printf ( "文字列、数値、文字をそれぞれ一行ずついれてください\n" ); s_print_string ( s_input_string() ); s_print_newline(); s_print_int ( s_input_int() ); s_print_newline(); s_print_char ( s_input_char() ); s_print_newline(); return 0; }
#include <stdio.h> #include "s_print.h" int main(void) { s_print_string ( " 13 % 5 = " ); s_print_int ( 13 % 5 ); s_print_newline(); s_print_string ( "-13 % 5 = " ); s_print_int ( -13 % 5 ); s_print_newline(); s_print_string ( " 13 % -5 = " ); s_print_int ( 13 % -5 ); s_print_newline(); s_print_string ( "-13 % -5 = " ); s_print_int ( -13 % -5 ); s_print_newline(); return 0; }
#include <stdio.h> /* getchar() が値を返す ( 入力した文字を返す ) */ int main(void) { putchar ( getchar() ); /* 返ってきた値が式の中で利用できる */ putchar ( '\n' ); return 0; }
#include <stdio.h> /* getchar() が返す値を式の中で利用する */ int main(void) { putchar ( getchar() + 1 ); /* 返ってきた値が式の中で利用できる */ putchar ( '\n' ); return 0; }
#include <stdio.h> /* getchar() が返す値を無視する事もできる */ int main(void) { getchar(); /* void 型の関数と同じ扱いが可能 */ /* 返された値は無視される */ /* 命令 ( キーボードから文字を入力する ) は実行される */ /* 値を返す関数の呼び出しで、値に興味がない場合は void 関数と同じように扱える */ /* 今回の場合は、「入力を待つ」という 振る舞い ( 副作用 : 関数の本来の目的は値を得る ) */ return 0; }
#include <stdio.h> /* 入力された文字を一文字ずらして、出力する */ int main(void) { /* main 関数の中で、すべてを行っている */ putchar ( getchar() + 1 ); putchar ( '\n' ); return 0; }
#include <stdio.h> /* 入力された文字を一文字ずらして、出力する input-process-output => process の部分を関数として切り出す 機能 : 文字をずらす */ /* char shift_char ( char ch ) 引数で指定された『文字』の次の『文字』を返す */ char shift_char ( char ch ) { /* 処理部分を関数の機能として切り出す */ /* => この関数の定義を別のソースに出して、再利用が可能 */ /* C 言語のプログラムでは main 関数が必須 */ /* => main 関数は再利用できない */ /* <= 再利用する場合は、関数として切り分ける */ return ch + 1; /* 一つ次の文字 */ } int main(void) { /* main 関数が I/O を担い、P は関数任せ */ putchar ( shift_char ( getchar() ) ); /* ^^^^^^^^^ 入力 */ /* ^^^^^^^^^^ 処理 */ /* ^^^^^^^ 出力 */ putchar ( '\n' ); return 0; }
#include <stdio.h> int main(void) { printf ( "Hello, " ); /* 命令(関数呼び出し)を並べた : 順接 */ printf ( "World" ); /* 並べた順に(複数の)命令が実行される */ printf ( "\n" ); /* 単純な命令組み合わせて複雑な命令を作る */ /* 命令の実行順序が指定できる */ return 0; }
#include <stdio.h> /* 引数で指定された文字が、 'j' => 日本語で 'e' (など 'j' 以外) => 英語で 条件分岐 複数の命令のどちらか一方を実行したい場合 cf. 順接(単に命令を並べる)だと、両方実行される */ void print_hello ( char ch ) { /* if 構文を利用して、条件分岐する */ if ( ch == 'j' /* 条件 */ ) { /* then 節 : 条件が成立した時の命令 */ printf ( "こんにちは、世界\n" ); /* 日本語 */ } else { /* else 節 : 条件が不成立の時 (成立以外) */ printf ( "Hello, World\n" ); /* 英語 */ } } int main(void) { print_hello ( getchar() ); return 0; }
#include <stdio.h> #include "s_print.h" #include "s_input.h" /* 値段(整数値)を入力して、わかりましたと答える その時に、値段が高い(10000以上は「高い」とする)場合だけ 「高い」 と文句を言う */ void print_pay ( int value ) { s_print_int ( value ); s_print_string ( "円ですね。わかりました。払います。\n" ); if ( value > 10000 ) { s_print_string ( "そんなに高いんですか ?\n" ); } else { /* 何かをするのは、高い場合だけ.. */ } } int main(void) { s_print_string ( "価格を整数値で入力してください : " ); print_pay ( s_input_int() ); return 0; }
#include <stdio.h> #include "s_print.h" #include "s_input.h" /* 値段(整数値)を入力して、わかりましたと答える その時に、値段が高い(10000以上は「高い」とする)場合だけ 「高い」 と文句を言う */ void print_pay ( int value ) { s_print_int ( value ); s_print_string ( "円ですね。わかりました。払います。\n" ); if ( value > 10000 ) { s_print_string ( "そんなに高いんですか ?\n" ); } /* else 節の省略 */ } int main(void) { s_print_string ( "価格を整数値で入力してください : " ); print_pay ( s_input_int() ); return 0; }
前回(2020/07/03)の内容 講義内容 「入力-処理-出力」 s_print.h/s_input.h の使い方 返値(かえりち)のある関数 s_print.h/s_input.h の使い方 2020/07/03 のページから、 c:\usr\c\include にダウロードする 使い方: C 言語のソースファイルの先頭に次の二行を追加 #include "s_print.h" => s_print_AAAA ( AAAA : char/int/string ) => char (文字), int (整数値), string (文字列) の出力が可能 #include "s_input.h" => s_input_AAAA ( AAAA : char/int/string ) => char (文字), int (整数値), string (文字列) の入力が可能 コンパイル時に、追加のコンパイルオプション -I ~/c/include を追加 従来 : cc -c foobar.c sを利用する場合 : cc -I ~/c/include -c foobar.c => リンク時は、従来と同じ 処理するデータの型が違うと、それを操作する関数が異なる データを処理する時には、常にそのデータの「型」を意識する必要がある 文字型(char)、整数型(int)、文字列(char *) 標準関数の入出力 出力 入力 文字型 putchar getchar 文字列 printf 未習得 整数型 未習得 未習得 非標準(s_) 出力 入力 文字型 s_print_char s_input_char 文字列 s_print_string s_input_string 整数型 s_print_int s_input_int 整数型 C 言語で整数値(の一部)を扱う int で整数型を表現する ( cf. char が文字型を表現 ) # int/char は型名 # 関数の仮引数変数の型宣言/関数の返り値の型 ! C 言語で、直接扱える整数値の範囲が ! - 2^31 ? 2^31-1 ! となっている。 ! => 有限の数値しか扱えない 整数のリテラル ( 整[定]数値を表す表現 ) (十進数の)構文:[符号(-)] ( 0 または 0 から始まらない数字並び ) 1, 123, -123, 0 整数の計算 四則 ( 和: +, 差: -, 積: *, 商: /, 余り: % ) の計算ができる a / b は整数割り算になる a / b = q .. r r = a % b a = b * q + r r = a - b * q 13 % 5= 13 - ( 13 / 5 ) * 5 = 13 - 2 * 5 = 13 - 10 = 3 -13 % 5= -13 - ( -13 / 5 ) * 5 = -13 - ( -2 ) * 5 = -13 - ( -10) = -3 13 % -5= 13 - ( 13 / -5 ) * -5 = 13 - ( -2 ) * -5 = 13 - ( 10) = 3 -13 % -5= -13 - ( -13 / -5 ) * -5 = -13 - ( 2 ) * -5 = -13 - ( -10) = -3 整数の比較 ( if 文で利用する ) 等価 ( 等しい: ==, 等しくない: != ) # C 言語では、等値比較のために「==」を使い「=」は使わない 大小比較 ( 大なり: >, 小さいなり: <, 以下: <=, 以上: >= ) !! 文字もでも同じ !! !! 内部的には、char 型の値(『文字』)は、 !! !! ASCII コード表に基づいて、小さな整数値 ( 0 ? 127 ) になっている !! !! # 本当は、char 型に関しては ( -128 ? 127 ) 整数の入出力 s_print_int()/s_input_int() を利用する 整数型の宣言 ( 引数/返り値 ) 「int」を利用する 返値(かえりち)のある関数 関数の定義 => 命令に名前をつけたもの # プログラムは、命令を並べたもの # 命令の並びに、名前を付けて、名前だけで呼び出せる # => 関数 !!! 数学で「関数」といれば、「値を入れると値が返るもの」 !!! 「値の対応関係」が「関数の機能」 !!! C 言語の「関数」は、void と宣言され値を返さない !!! cf. getchar() は「文字を返す関数」 !!! cf. main() は「整数値を返す関数」 C 言語でも、「値を返す『関数』」が定義できる 新しい点 関数名の前に void => 関数値の「型」(char,int,char *) return 命令 return 式; => 式の値を計算し、関数の返り値とする return 命令を実行すると、その時点で関数が終了する # void 関数(値を返さない関数) # でも、return; (式を書かない)が使えて、 # その場で、関数を終了させる機能が使える その関数が値を返すので、その値を利用する「式」の中で利用できる cf. void 関数は、関数呼び出しを文としてしか使えない 例 : void f(); => 「f()+1」かけない int g(); => 「g()+1」として、関数の値を利用できる !!! 関数の利用法 !!! void 関数 : f(); <= 関数 f を呼び出す !!! 値を返す関数 : g(); <= void と同じにできる !!! => 関数 g()が返した値は捨てられる 「入力-処理-出力」 プログラムの構成の仕方 言語を学ぶ => 意味を表すために、構文規則に沿って表現をする手段 「C 言語での表現方法」を学ぶ事が「ソフトウェア概論の目的」 => 表現したい対象があって その対象を「構成」する必要がある 上司が失敗した部下を叱る時 まず、失敗を指摘して叱る 次に、ほめて、やる気を出させる 逆にすると: 最初にほめて、て叱る => 落差がおおきくなって、より落ち込む 個々の表現だけでなく、表現の組み合わせが重要 プログラムの構成の仕方 複雑なものを簡単なものの組み合わせにしたい(分割統治) どのように分割するか ? 分割の指標 : 「入力-処理-出力」 main データ入力 関数に引数としてデータを渡して処理 出力 a) 関数内 b) 値を返して、それ main で出力 b) => 入出力を main にまとめて、 処理の部分を関数に集中させる事により、 プログラムの構成や意味がわかりやすくなる [2020/07/10] 条件分岐 (if 構文) 条件分岐 複数の命令の内、 条件によって、 その複数の命令の内の、いずれか一つ を実行する仕組み cf. 順接 : 命令を並べる事により、 複数の命令を、並べた順に、それぞれ実行する仕組み => 記述量がふえると、実行量が増える 与えれた状況に併せて、適切な対応を選択する仕組み プログラムの柔軟性を高める仕組み if 構文 : 条件分岐を実現する C 言語での表現方法 構文 : if ( 条件式 ) { then 節 条件が不成立時の文 } else { else 節 条件が成立時の文 } 条件式 : 真偽値(成立/不成立)を求める式 真 => 条件が成立 偽 => 条件が不成立 ( 成立しなかった ) 例: !strcmp ( A, B ) => A,B が同じ文字列なら真 例: 整数型の値や文字型の値は「比較」ができる ==, != (等しい、等しくない) <, >, <=, >= で、大小比較が可能 条件の成立時の文 条件が不成立時の文 : 複数の文(命令)が指定できる ( 空にする事も可能 ) 意味 「条件」が 『成立』した時に「条件の成立時の文」 を、 そうでない時には、「条件が不成立時の文」 を 実行する どちらか 一方だけ が実行される 両方実行も両方不実行もなし 「if 『文』」ではなく、 「if 『構文』」である理由 「『文』を対象として、『何かをする表現』」 なので「メタ表現」 文は、データを対象とする表現 構文は、文を対象とする表現 cf. 「順接」も「順接構文」 if 構文 アラカルト if 構文の基本 : if ( C ) { A } else { B } 「基本」は「基本の組み合せだけで何でもできる」ので秀逸 色々な組み合せ方を学ぶ必要がある else 節の省略 else 節 : if 構文の 「else { B }」の部分 B が空の時は、 「else {}」としても良い が、 それを省略しても良い 基本: if ( C ) { A } else { } else 節の省略の場合: if ( C ) { A } /* else {} */ /* else 節を省略 */ then 節 ( { A } の所 ) は省略できない 基本: if ( C ) { } else { B } できない: if ( C ) else { B } if 構文の「入れ子」 if 構文の文の中に if 構文をいれる 複数の条件の「条件の組み合せ」を if 構文の組み合せで実現できる 例(複雑な条件) : ch が英大文字かどうか 'A' <= ch <= 'Z' [数学] => C 言語では、こう表現できません # 別の表現があるが、後期に話す 例 : if ( 'A' <= ch ) { /* ここでは、 「'A' <= ch」が成立している */ if ( ch <= 'Z' ) { /* ここでは「'A' <= ch」と「ch <= 'Z'」の両方が成立 */ /* ch が「英大文字」の時 */ } else {} } else {} else if 構文 (イデオム) else 節の文全体が if 構文(入れ子)になっている場合 else 節のブレースを省略する 例: if ( C1 ) { A } else { if ( C2 ) { B } else { C } } => if ( C1 ) { A } else if ( C2 ) { B } else { C } 入れ子による、段の深化が防げる 一つのデータに対して、複数の条件の検査になっている 「表現」と「意味」の対応 (イデオム)
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20200710-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
$ ./20200710-01-QQQQ.exe 国を表す文字を入力してください j 日本 e 英語 c 中国 f フランス g ドイツ Bonjour $
Download : 20200710-02.c
/* * 20200710-02-QQQQ.c * 入力された文字の字種を答える関数 */ #include <stdio.h> /* * print_chractor_type ( char ch ) * 引数で指定された文字の種類 ( 大英文字、小英文字、数字、その他 ) * を判定し、その種類を表示する */ void print_chractor_type ( char ch ) { /* まず、英大文字かどうかを判定 */ if ( 'A' <= ch ) { /* 'A' 以上で.. */ if ( ch <= 'Z' ) { /* 'Z' 以下なので.. */ putchar ( ch ); printf ( " は、英大文字です。\n" ); return; /* ここで関数を終了 ( 返り値はない ) */ } /* else {} */ /* else 節は省略 */ } /* else {} */ /* else 節は省略 */ /* まず、次は英小大かどうかを判定 */ if ( 'a' <= ch ) { /* ** この部分を完成させなさい */ } /* 最後に、数字かどうかを判定 */ if ( '0' <= ch ) { if ( ch <= '9' ) { putchar ( ch ); printf ( " は、数字です。\n" ); return; } } /* ここまで何かの条件が成立すれば return で終了している筈 */ /* ここにきたという事は、どの条件も成立していないので、「その他」と判定して良い */ putchar ( ch ); printf ( " は、その他です。\n" ); return; /* この return は不要だが、省略しない方が良い */ } /* * main */ int main ( void ) { printf ( "キーボードから一文字入力すれば、文字の種類を表示します : " ); print_chractor_type ( getchar() ); return 0; }
v
$ ./20200710-02-QQQQ.exe キーボードから一文字入力すれば、文字の種類を表示します : v は、英子文字です。 $