Download : sample-001.c
/* * 2021/06/18 sample-001.c */ /* * 返値を持つ関数 */ #include <stdio.h> /* * to_upper : 引数で与えられた文字が小文字なら大文字にする */ char to_upper ( char ch ) { if ( 'a' <= ch ) { /* もし、ch が 'a' 以上で.. */ if ( ch <= 'z' ) { /* 更に、ch が 'z' 以下なら.. */ return ch - 'a' + 'A'; /* 小文字なので大文字に変換して返す */ /* return 命令が実行されると、そこで関数は終了 */ } /* else {} */ /* else 以下はないので省略 */ } /* else {} */ return ch; /* 小文字でない場合は、そのまま返す */ } /* * main 関数 */ int main ( void ) { printf ( "一文字入力して、[Enter] キーを押してください : " ); putchar ( to_upper ( getchar() ) ); putchar ( '\n' ); return 0; }
k
$ ./sample-001.exe < sample-001.in 一文字入力して、[Enter] キーを押してください : k K $
Download : sample-002.c
/* * 2021/06/18 sample-002.c */ /* * main の返値 */ #include <stdio.h> /* * is_upper : ch が大文字なら 1 そうでなければ、0 を返す */ int is_upper ( int ch ) { if ( 'A' <= ch ) { if ( ch <= 'Z' ) { return 1; /* 大文字だった.. */ } } return 0; /* 大文字ではなかった.. */ } /* * main 関数 */ int main ( void ) { printf ( "一文字入力して、[Enter] キーを押してください : " ); if ( is_upper ( getchar() ) ) { printf ( "大文字なので 0 を返します。\n" ); return 0; } else { printf ( "大文字でなかったので 1 を返します。\n" ); return 1; } }
Q
$ ./sample-002.exe < sample-002.in 一文字入力して、[Enter] キーを押してください : Q 大文字なので 0 を返します。 $
Download : sample-003.c
/* * 2021/06/18 sample-003.c * * コンパイルの方法: * cc -c -I ~/c/include sample-003.c */ /* * s_print.h の使い方 */ #include <stdio.h> #include "s_print.h" /* s_print_... を利用する場合には必要 */ /* * main 関数 */ int main ( void ) { s_print_char ( 'A' ); /* 文字の出力 : putchar ( 'A' ) と同じ */ s_print_newline(); /* 改行の出力 : putchar ( '\n' ) と同じ */ s_print_string ( "Hello, World\n" ); /* 文字列の出力 : printf と同じ */ s_print_int ( 123 ); /* 整数値の出力 */ s_print_newline(); return 0; }
$ ./sample-003.exe A Hello, World 123 $
Download : sample-004.c
/* * 2021/06/18 sample-004.c * * コンパイルの方法: * cc -c -I ~/c/include sample-004.c */ /* * s_input.h の使い方 */ #include <stdio.h> #include "s_print.h" #include "s_input.h" /* s_input_... を利用する場合には必要 */ /* * main 関数 */ int main ( void ) { s_print_string ( "一文字を入力して、[Enter] を押してください : " ); s_print_char ( s_input_char () + 1 ); s_print_newline(); s_print_string ( "整数値を一つ入力して、[Enter] を押してください : " ); s_print_int ( s_input_int () + 1 ); s_print_newline(); return 0; }
B 123
$ ./sample-004.exe < sample-004.in 一文字を入力して、[Enter] を押してください : B C 整数値を一つ入力して、[Enter] を押してください : 123 124 $
Download : sample-005.c
/* * 2021/06/18 sample-005.c * * コンパイルの方法: * cc -c -I ~/c/include sample-005.c */ /* * 二つの入力を利用する場合 */ #include <stdio.h> #include "s_print.h" #include "s_input.h" /* * addfunc */ int addfunc ( int a ) { s_print_string ( "二つ目の整数値を入力して、[Enter] を押してください : " ); return a + s_input_int(); } /* * main 関数 */ int main ( void ) { s_print_string ( "一つ目の整数値を入力して、[Enter] を押してください : " ); s_print_int ( addfunc ( s_input_int() ) ); s_print_newline(); return 0; }
123 456
$ ./sample-005.exe < sample-005.in 一つ目の整数値を入力して、[Enter] を押してください : 123 二つ目の整数値を入力して、[Enter] を押してください : 456 579 $
Download : sample-006.c
/* * 2021/06/18 sample-006.c * * コンパイルの方法: * cc -c -I ~/c/include sample-006.c */ /* * 二つの入力を利用する場合 (失敗例) */ #include <stdio.h> #include "s_print.h" #include "s_input.h" /* * subfunc */ int subfunc ( int a, int b ) { return a - b; } /* * main 関数 */ int main ( void ) { s_print_string ( "二つの整数値を入力して、[Enter] を押してください : " ); s_print_int ( subfunc ( s_input_int(), s_input_int() ) ); s_print_newline(); return 0; }
123 456
$ ./sample-006.exe < sample-006.in 二つの整数値を入力して、[Enter] を押してください : 123 456 333 $
/* * 20210611-02-QQQQ.c * 指定した文字列の中の英小文字を英大文字に、英大文字を英小文字に入れ替えて出力する関数 */ #include <stdio.h> #include <string.h> /* 以下の結果は、20210611-01-QQQQ.c の内容を、そのまま利用する */ /* * char change_up_lower ( char ch ) * 引数で指定された文字が大英文字なら英小文字に、英小文字なら英大文字にする */ char change_up_lower ( char ch ) { /* 英大文字の処理 */ /* 'A' ? 'Z' */ /* 'A' <= ch <= 'Z' */ /* => 二つの条件 */ /* 'A' <= ch と ch <= 'Z' */ if ( 'A' <= ch ) { /* もし、 ch が 'A' 以上で .. */ if ( ch <= 'Z' ) { /* しかも、 'Z' 以下 なら .. */ /* ここに来るのは、二つ条件が共に成立した場合 */ /* 引数は英大文字だったので、英小文字に変換し、値を返す */ return ch - 'A' + 'a'; /* 大文字から小文字への変換 */ /* 上の return 命令が実行されると、その時点で、 関数実行が終了する */ } else {} } else {} /* ここにきた場合は、「大文字じゃなかった」場合.. */ /* ch が大文字なら、return 命令が実行され、ここにはこない */ /* 英小文字の処理 */ if ( 'a' <= ch ) { /* もし、 ch が 'a' 以上で .. */ if ( ch <= 'z' ) { /* しかも、 'z' 以下 なら .. */ /* 引数は英小文字だったので、英大文字に変換し、値を返す */ return ch - 'a' + 'A'; /* 小文字から大文字への変換 */ } } /* 何れでもない場合 */ /* 大文字でも小文字でもない場合 */ return ch; /* 引数の値をそのまま、関数の値として返す */ } /* * void print_change_up_lower_string ( char *string ) * 引数で指定した文字列の中の英小文字を英大文字に、 * 英大文字を英小文字に入れ替えて出力する関数 */ void print_change_up_lower_string ( char *string ) { if ( !strcmp ( string, "" ) ) { /* 空文字列 ("") だった.. */ /* 何もしない */ } else { /* 取り敢えず、先頭の文字だけ変換を行って、出力 */ putchar ( change_up_lower ( *string ) ); /* 残りの文字列は、再帰で処理 */ print_change_up_lower_string ( string + 1 ); } } /* * main */ int main ( void ) { printf ( "Aa0BB11cc@+Xy\n" ); print_change_up_lower_string ( "Aa0BB11cc@+Xy\n" ); return 0; }
/* * 20210611-03-QQQQ.c * 10 未満の長さの文字列の長さを表す一文字の数字を返す関数 * "abc" -> '3' * "12345" -> '5' * 考え方: * "" -> '0' 単純な例 * "1" -> '1' * "12345" -> '5' * "12345" -> '5' * '4' = '5' - 1 * "2345" = "12345" + 1 * 求めたい関数を f() で表す * f("12345") = '5' * = '4' + 1 * = f("2345") + 1 * = f("12345"+1) + 1 * f(S) = f(S+1)+1 */ #include <stdio.h> #include <string.h> /* * char length_of_string ( char *string ) * 引数の文字列の長さを表す、一桁の数字を返す関数 * 文字列の長さは一桁の場合しか、「適切に動作」しない */ char length_of_string ( char *string ) { if ( !strcmp(string,"") ) { /* 空文字列なら、長さは 0 */ return '0'; /* 長さ「0」を表す『文字(数字)』「'0'」を返す */ } else { /* 一文字分短い『文字列』の長さを再帰で求め、それに 1 を加える */ return length_of_string ( string + 1 ) + 1; /* f(S) = f(S+1)+1 */ } } /* * main */ int main ( void ) { printf ( "文字列「\"abc\"」の長さは " ); putchar ( length_of_string ( "abc" ) ); printf ( " です。\n" ); printf ( "文字列「\"123456\"」の長さは " ); putchar ( length_of_string ( "123456" ) ); printf ( " です。\n" ); /* 長さが 10 を越える場合は、不適切な結果になる */ printf ( "文字列「\"1234567890123\"」の長さは " ); putchar ( length_of_string ( "1234567890123" ) ); printf ( " です。\n" ); return 0; }
/* * 20210618-01-QQQQ.c * 文字の種類に応じて、その種類を表す文字を返す関数 * 種別 範囲 返す文字 * 英大文字 A-Z A * 英子文字 a-z a * 数字 0-9 0 * その他 ? */ #include <stdio.h> /* * char_type : 引数で与えられた文字の種類を表す文字を返す関数 */ char char_type ( char ch ) { /* 英大文字かどうかをチェック */ /* 'A' <= ch <= 'Z' */ if ( 'A' <= ch ) { /* もし、ch が 'A' 以上で.. */ if ( ch <= 'Z' ) { /* 更に、ch が 'Z' 以下なら.. */ /* ここにくるということは、英大文字 */ return 'A'; /* 'A' を返す */ } /* else {} */ /* else 以下はないので省略 */ } /* else {} */ /* else 節が空の場合は、else ごと省略してよい */ /* 英小文字かどうかをチェック */ if ( 'a' <= ch ) { /* もし、ch が 'a' 以上で.. */ if ( ch <= 'z' ) { /* 更に、ch が 'z' 以下なら.. */ return 'a'; /* 英小文字なので 'A' を返す */ } /* else {} */ /* else 以下はないので省略 */ } /* else {} */ /* 数字かどうかをチェック */ /* '0' <= ch <= '9' */ /* '0' <= ch, ch <= '9' の二つの条件をチェック */ if ( '0' <= ch ) { /* もし、ch が '0' 以上で.. */ if ( ch <= '9' ) { return '0'; } /* else {} */ } /* else {} */ /* 上記のいずれでもない場合は、'?' を返す */ return '?'; } /* * change_char_type : 一行分、キーボードから文字列を読込、そのタイプに変換 */ void change_char_type ( char ch ) { if ( ch == '\n' ) { /* 改行ならば、一行分の処理は終り */ /* do nothing */ } else { /* 文字のタイプを表示し、再帰処理 */ putchar ( char_type ( ch ) ); change_char_type ( getchar() ); } } /* * main 関数 */ int main ( void ) { printf ( "一行文字列入力して、[Enter] キーを押してください : " ); change_char_type ( getchar() ); putchar ( '\n' ); return 0; }
#include <stdio.h> int main(void) { printf ( "1. Hello, World\n" ); /* 命令: メッセージを画面出力する */ printf ( "2. Hello, World\n" ); /* 命令を並べる : 順接 */ printf ( "3. Hello, World\n" ); return 0; }
#include <stdio.h> #include <string.h> /* strcmp を利用する場合 */ /* stdio.h の中に printf の extern 宣言がある */ /* 同様に、string.h の中に strcmp の宣言がある */ int main(void) { if ( !strcmp ( "abc", "abc" ) ) { /* 二つの文字列は等しい */ printf ( "二つの文字列は等しい\n" ); /* こちらの命令が実行される */ } else { printf ( "二つの文字列は等しくない\n" ); } if ( !strcmp ( "abc", "xyz" ) ) { /* 二つの文字列は等しくない */ printf ( "二つの文字列は等しい\n" ); } else { printf ( "二つの文字列は等しくない\n" ); /* こちらの命令が実行される */ } return 0; }
#include <stdio.h> #include <string.h> /* あて名書き 先生の名前の場合は、「先生」それ以外は「様」を付ける 栗野、渡辺 => 先生 その他 => 様 */ void atena ( char *name ) { if ( !strcmp ( name, "栗野" ) ) { printf ( name ); printf ( "先生\n" ); } else { /* if 構文の「入れ子」を行っている */ /* => if 構文の中で、さらに if 構文を利用している */ if ( !strcmp ( name, "渡辺" ) ) { printf ( name ); printf ( "先生\n" ); } else { printf ( name ); printf ( "様\n" ); } } } int main(void) { atena ( "鈴木" ); atena ( "佐藤" ); atena ( "栗野" ); atena ( "渡辺" ); return 0; }
#include <stdio.h> #include <string.h> /* あて名書き 先生の名前の場合は、「先生」それ以外は「様」を付ける 栗野、渡辺 => 先生 その他 => 様 新しい版 : 小紫先生の名前もあつかえるようにした */ void atena ( char *name ) { if ( !strcmp ( name, "栗野" ) ) { printf ( name ); printf ( "先生\n" ); } else { /* if 構文の「入れ子」を行っている */ /* => if 構文の中で、さらに if 構文を利用している */ if ( !strcmp ( name, "渡辺" ) ) { printf ( name ); printf ( "先生\n" ); } else { /* さらに入れ子になっている */ if ( !strcmp ( name, "小紫" ) ) { printf ( name ); printf ( "先生\n" ); } else { printf ( name ); printf ( "様\n" ); } } } } int main(void) { atena ( "小紫" ); atena ( "鈴木" ); atena ( "佐藤" ); atena ( "栗野" ); atena ( "渡辺" ); return 0; }
#include <stdio.h> #include <string.h> /* あて名書き 先生の名前の場合は、「先生」それ以外は「様」を付ける 栗野、渡辺 => 先生 その他 => 様 新しい版 : 小紫先生の名前もあつかえるようにした */ void atena ( char *name ) { if ( !strcmp ( name, "栗野" ) ) { printf ( name ); printf ( "先生\n" ); } else if ( !strcmp ( name, "渡辺" ) ) { printf ( name ); printf ( "先生\n" ); } else if ( !strcmp ( name, "小紫" ) ) { printf ( name ); printf ( "先生\n" ); } else { printf ( name ); printf ( "様\n" ); } } int main(void) { atena ( "小紫" ); atena ( "鈴木" ); atena ( "佐藤" ); atena ( "栗野" ); atena ( "渡辺" ); return 0; }
#include <stdio.h> void rec_func(void) { /* 関数 rec_func の定義 */ printf ( "Hello, World\n" ); rec_func(); /* 本体で、自分自身 (rec_func())を呼び出す */ } int main(void) { rec_func(); /* rec_func() => printf ( "Hello, World\n" ); => 「Hello, World」と表示 rec_func(); => printf ( "Hello, World\n" ); => 「Hello, World」と表示 rec_func(); => printf ( "Hello, World\n" ); => 「Hello, World」と表示 rec_func(); .... 延々と「Hello, World」と表示続ける */ return 0; }
#include <stdio.h> #include <string.h> void rec_func( char *length ) { /* 関数 rec_func の定義 */ /* length は、1 進法で、繰り返す回数を表す */ /* => length で指定された文字列の文字の個数回だけ繰り返す */ if ( !strcmp( length, "" ) ) { /* 条件成立 : 繰り返しをやめる条件 */ /* 繰り返す回数が 0 の時は、やめてよい */ /* => 引数 length の長さが 0 */ /* 再帰呼び出しをしなければなんでもよい(特に、空でもよい) */ } else { /* 条件が不成立の時に、再帰呼び出し (繰り返す) */ printf ( "Hello, World\n" ); /* <= 繰り返されるのはこの命令 */ rec_func( length + 1 ); /* 本体で、自分自身 (rec_func())を呼び出す */ /* 引数の値を変更:変更を繰り返す事により、 最終的に、繰り返しが終了するように書き換える */ /* 文字列 に対して 1 を加えると、 文字列の長さが 1 だけ短くなる */ } } int main(void) { rec_func( "***" ); /* 長さ 3 の文字列を指定する */ /* rec_func( "***" ) => "***" -> length if ( !strcmp( length, "" ) ) { } else { printf ( "Hello, World\n" ); rec_func( length + 1 ); } => if ( !strcmp( "***", "" ) ) { } else { printf ( "Hello, World\n" ); rec_func( "***" + 1 ); } => printf ( "Hello, World\n" ); 命令を一回繰り返すと同時 rec_func( "**" ); 文字列の長さが 1 減る => -> 「Hello, World」 "**" -> length if ( !strcmp( length, "" ) ) { } else { printf ( "Hello, World\n" ); rec_func( length + 1 ); } => -> 「Hello, World」 if ( !strcmp( "**", "" ) ) { } else { printf ( "Hello, World\n" ); rec_func( "**" + 1 ); } => -> 「Hello, World」 printf ( "Hello, World\n" ); rec_func( "*" ); => -> 「Hello, World」 -> 「Hello, World」 "*" -> length if ( !strcmp( length, "" ) ) { } else { printf ( "Hello, World\n" ); rec_func( length + 1 ); } => -> 「Hello, World」 -> 「Hello, World」 if ( !strcmp( "*", "" ) ) { } else { printf ( "Hello, World\n" ); rec_func( "*" + 1 ); } => -> 「Hello, World」 -> 「Hello, World」 printf ( "Hello, World\n" ); rec_func( "" ); => -> 「Hello, World」 -> 「Hello, World」 -> 「Hello, World」 "" -> length if ( !strcmp( length, "" ) ) { } else { printf ( "Hello, World\n" ); rec_func( length + 1 ); } => -> 「Hello, World」 -> 「Hello, World」 -> 「Hello, World」 if ( !strcmp( "", "" ) ) { } else { printf ( "Hello, World\n" ); rec_func( "" + 1 ); } => -> 「Hello, World」 -> 「Hello, World」 -> 「Hello, World」 */ return 0; }
#include <stdio.h> #include <string.h> /* 繰り返しのイデオム 命令 A を、引数で指定した文字列の長さだけ実行するには 次のような再帰呼び出しのパターンを利用すればよい void rec_A ( char *lengh ) { if ( !strcmp ( length, "" ) ) { } else { 命令 A rec_A ( length + 1 ); } } と、関数 rec_A を定義し、実引数に、 命令 A を繰り返したい回数の長さの文字列を指定すればよい */ void func ( void ) { printf ( "Hello, World\n" ); } void rec_func( char *length ) { if ( !strcmp( length, "" ) ) { } else { func(); /* 繰り返される命令 */ rec_func( length + 1 ); } } int main(void) { rec_func( "***" ); /* 長さ 3 の文字列を指定する */ return 0; }
#include <stdio.h> /* 関数定義 */ void printHello (void) { printf ( "Hello, World\n" ); } int main(void) { /* 関数呼び出し */ printHello(); return 0; }
#include <stdio.h> /* 引数付き関数の定義 */ /* 関数定義の頭部で、仮引数変数宣言を行う 関数定義の本体で、その仮引数変数を含む命令を書く => 命令の一部を、変数に置き換える */ void printSomething (char *any) { /* any に文字列が入る場合 */ printf ( "Hello, " ); printf ( any ); /* 後から、別の物 (any) を出したい */ printf ( "\n" ); } int main(void) { /* 関数呼び出し */ /* 関数本体に現れる変数に入れる値を実引数として与える */ printSomething( "World" ); /* Hello, World と出力される */ printSomething( "世界" ); /* Hello, 世界と出力される */ return 0; }
#include <stdio.h> int main(void) { printf ( "A" ); /* 文字列「A」を出力する */ putchar ( 'A' ); /* 文字「A」を出力する */ /* 文字列を出力する関数と文字を出力する関数が異なる */ /* => 文字列と文字は型が異なる 処理の仕方が異なる 同じ事をしても、違う結果になったり、 例: 「文字列 + 1」, 「文字 + 1」 同じ +1 なのに、結果が違う 文字列 => 先頭の文字が欠けて、一文字分短くなる 文字 => ASCII コード表の次の文字になる できる事とできない事がある 例: 「*文字列」 はできる (先頭の文字を取り出す) 「*文字」 はできない */ printf ( "\n" ); /* 改行 */ return 0; }
#include <stdio.h> void sp( char *x ) { printf ( x ); /* 変数 x に入る値は文字列である事が想定される */ } void cp( char x ) { putchar ( x ); /* 変数 x に入る値は、文字である事が想定される */ } /* 値を直接指定する場合は、型を間違える事が少ないが、 変数を経由すると、その変数に入っている値の型が見えないので、 型を間違える(不適切な型の値を指定してしまう)危険がある 型宣言(変数に入る値の型を指定する)事により、 その誤りをコンパイラがチェックしてくれる */ int main(void) { sp( "A" ); /* 実引数には、仮引数変数で宣言されている型の値を指定する */ cp( 'A' ); printf ( "\n" ); /* 改行 */ return 0; }
#include <stdio.h> void sp( char *x ) { printf ( x ); } void cp( char x ) { putchar ( x ); } int main(void) { sp( 'A' ); /* 実引数の型と仮引数変数の型が異なる */ cp( "A" ); /* 間違った指定をした場合にエラーになる */ printf ( "\n" ); /* 改行 */ return 0; }
#include <stdio.h> int main(void) { putchar(getchar()+1); /* getchar() で、キーボードから一文字読み込む */ /* getchar() の返した値を putchar() で出力する */ return 0; }
#include <stdio.h> /* +1 の部分を関数にしたい.. */ /* 文字から(ASCII コード表の次の)文字にしたい 値を持つ */ char inc(char ch) { /* 文字から文字なので返り値の型と引数型をそれぞれ char */ /* 値として返したいものは、与えられた文字の次の文字 ( +1 した文字 ) */ return ch + 1; /* 「ch+1」という式の値を計算し、その計算結果を関数の返り値としてしてし さらに、関数を即座に終了する */ } int main(void) { putchar(inc(getchar())); /* getchar() で、キーボードから一文字読み込む */ /* getchar() の返した値を putchar() で出力する */ return 0; }
#include <stdio.h> #include "s_print.h" /* s_print.h は「"」で挟む */ #include "s_input.h" int main(void) { /* s_print_string */ s_print_string ( "Hello, World\n" ); s_print_int ( 123 ); /* 整数値を出力する */ s_print_newline(); /* 改行を出力する */ s_print_int ( 123 + 456 ); /* 整数の計算式は計算されて出力される */ s_print_newline(); /* 改行を出力する */ s_print_string ( "整数値を入力してください。倍にして表示します\n" ); s_print_int ( s_input_int() * 2 ); s_print_newline(); /* printf ( "Hello, World\n" ); */ return 0; }
前回(2021/06/11)の内容 先々週から、二周目(最初から、詳しくもう一度) Hello, World 色々なおまじない(例:#include)の解説 制御構造 先週(二周目) 「関数」という考え方 「プログラムの一部(命令)」に「名前」を付ける事 !!! 命令列は、「順接」を複数の命令に適用したもの !!! なので、結局、一つの「命令」になっている !!! => 関数呼び出しは、一つの「命令」 関数の定義方法 命令列に名前を付ける事 書き方 0. 名前をきめて、それを書く 1. 名前の前に void、後ろに (void) 2. その続きに {, } 3. { と } の間に名前を付けたい命令(列)を書く 関数の呼出し方法 名前を付けた、命令を、その名前(関数名)を利用して、 呼び出す表現 書き方 0. 関数名書き 1. 名前の後ろに (); を付ける 引数付き関数 名前をつける命令の中に、変数を含める事により、 後から、変数の値を指定する事により、 同じ命令なのに、異なる振る舞いさせる事ができる 記述方法 定義 仮引数変数の宣言を行う 呼び出し 実引数を指定する 仮引数変数の宣言の時 変数の名前と同時、(その前に..) その変数に入る値の型を指定する必要がある 具体例: 文字列の時 char * 文字 char 文字を引数に持つ関数と型宣言 文字を引数に持つ関数 : char * から char 仮引数変数の「型宣言」 (実引数として与えられる)値の型がわからないと、 その値を利用する(演算する)方法がわからない => 型を指定する事によって、 値の処理の方法を指示する必要がある 「文字」というデータ型 「文字」の比較 / 「文字」の計算 出力には putchar を使う / getchar で入力ができる C 言語の関数にも「値」を持つ(返す)ものがある => 最初の例と紹介したのが getchar() 入力-処理-出力 ( Input - Process - Output ) 例: p-014.c input -> getchar() process -> +1 <= 目的 output -> putchar() getchar() キーボードから文字を入力して、それを値とする関数 値を返す関数 (1) 今までの関数と違い 1. 関数前にある void -> 関数が返す値の型 2. 本体に 「return 式」命令を書く事により、 関数の値を return の後ろの「式」で指定できる 「return 式」命令には二つ機能がある a) この命令を実行すると、即座に関数を終了する => 制御構造 ( 命令の実行順序に影響を与える .. ) b) 関数の終了に際して、return の後ろにある式の値を関数の返り値にする 2021/06/18 順接 命令を並べると、その命令が、並べた順に実行される cf. プログラム : 命令を並べたもの 命令(C 言語における命令の典型的な形:関数呼び出し) 関数呼び出し ( printf 関数を呼び出す ) => 関数に機能が働いて、「何か」がおきる 具体例 : printf ( 文字列 ) => 文字列が画面に表示される putchar ( 文字 ) => 文字が画面に表示される 個々の関数が何をするかは、すこしずつ学ぶ必要がある 「命令と命令を組み合わせて、新しい命令を作る」 『命令』を対象する記述(一種のメタ命令) => 制御構造 条件分岐 if 構文 ( <= 「if 『文』」とは呼ばない ) !!! if 構文 : 命令とは次元が異なる if ( 条件 ) { 条件が成立した時の命令A /* then 節 */ } else { 条件が不成立の時の命令B /* else 節 */ } if 構文によって、命令A と命令 B から、 新しい命令が作られる 「文」<= 命令に対して使う言葉 条件 文字列の比較の場合 !strcmp ( A, B ) 文字列 A と B が等しい 文字の比較の場合 A == B 等しい文字 A != B 等しく文字 A < B 文字 A が ASCII コード表順で B より小さい A > B 〃 大きい A <= B 文字 A が ASCII コード表順で B より以下 A >= B 〃 以上 !! 「=>」という比較演算子はない if 構文(条件分岐)を利用すると、 条件によって、二つの命令のどちらか一方を実行するような (新しい)命令が作られる => if 構文を「入れ子」にする事により、 二つより多くの命令のいずれか一つを実行するようにできる else if 構文 else 節全体が一つの if 構文の時、 else 節を囲む { と } を省略する表現 繰り返し 再帰呼び出しを利用する事により、 与えられた命令を、繰り返すよう新しい命令が作れる 再帰呼び出しの書き方 => 関数を定義する時に、関数の本体に、自分自身を呼び出す !! 注意 !! 無条件に再帰呼び出しをすると、無限ループになる !! 「与えられた命令を繰り返す(新しい)命令」を作る !! <= 上手に、適当なところで、繰り返しをやめるようにする !! if 構文を利用して、 !! 再帰呼び出しをする命令とそうでない命令を組み合わせる !! if 構文の条件のところに変数がないとこまる !! その変数は、関数の引数に基づくものである必要があり !! その引数は、再帰呼び出しの時に変更されないといけない !! その変更の結果、いつかは、再帰呼び出しをしない命令が if 構文により実行される必要がある 三つの制御構造 ( 順接、条件分岐、繰り返し ) があれば、 実は、任意の命令が、この制御構造の繰り返し適用で、実現可能な事が(数学的に..)わかっている == s_print.h s_input.h の使い方 1. プログラムの先頭 ( stdio.h の下位.. ) #include "s_print.h" #include "s_input.h" 書く 2. コンパイルする時に 「-I ~/c/include」を -c の前に挿入する cc -I ~/c/include -c p-016.c ^^^^^^^^^^^^^^^ 追加部分 3. 次の関数が使える s_print.h s_print_string 文字列の出力 ( printf と同じ ) s_print_char 文字の出力 ( putchar と同じ ) s_print_int 整数値の出力 s_input.h s_input_string 文字列の入力 s_input_char 文字の入力 ( getchar と同じ ) s_input_int 整数値の入力 s_input/s_print
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20210618-01.c
/* * 20210618-01-QQQQ.c * 文字の種類に応じて、その種類を表す文字を返す関数 * 種別 範囲 返す文字 * 英大文字 A-Z A * 英子文字 a-z a * 数字 0-9 0 * その他 ? */ #include <stdio.h> /* * char_type : 引数で与えられた文字の種類を表す文字を返す関数 */ char char_type ( char ch ) { /* 英大文字かどうかをチェック */ if ( 'A' <= ch ) { /* もし、ch が 'A' 以上で.. */ if ( ch <= 'Z' ) { /* 更に、ch が 'Z' 以下なら.. */ /* ** この部分を完成させなさい */ } /* else {} */ /* else 以下はないので省略 */ } /* else {} */ /* 英小文字かどうかをチェック */ if ( 'a' <= ch ) { /* もし、ch が 'a' 以上で.. */ if ( ch <= 'z' ) { /* 更に、ch が 'z' 以下なら.. */ return 'a'; /* 英小文字なので 'A' を返す */ } /* else {} */ /* else 以下はないので省略 */ } /* else {} */ /* 数字かどうかをチェック */ if ( '0' <= ch ) { /* もし、ch が '0' 以上で.. */ /* ** この部分を完成させなさい */ } /* else {} */ /* 上記のいずれでもない場合は、'?' を返す */ /* ** この部分を完成させなさい */ } /* * change_char_type : 一行分、キーボードから文字列を読込、そのタイプに変換 */ void change_char_type ( char ch ) { if ( ch == '\n' ) { /* 改行ならば、一行分の処理は終り */ /* do nothing */ } else { /* 文字のタイプを表示し、再帰処理 */ putchar ( char_type ( ch ) ); change_char_type ( getchar() ); } } /* * main 関数 */ int main ( void ) { printf ( "一行文字列入力して、[Enter] キーを押してください : " ); change_char_type ( getchar() ); putchar ( '\n' ); return 0; }
abcABC123()~
$ ./20210618-01-QQQQ.exe 一行文字列入力して、[Enter] キーを押してください : aaaAAA000*** $
Download : 20210618-02.c
/* * 20210618-02-QQQQ.c * 二つの整数値を入力して、その余りを出力する */ #include <stdio.h> #include "s_print.h" #include "s_input.h" /* * remainder */ int remainder ( int a ) { s_print_string ( "割る整数を入力して、[Enter] を押してください : " ); /* ** この部分を完成させなさい */ } /* * main */ int main ( void ) { s_print_string ( "割られる整数を入力して、[Enter] を押してください : " ); s_print_int ( remainder ( s_input_int() ) ); s_print_newline(); return 0; }
100 13
$ ./20210618-02-QQQQ.exe 割られる整数を入力して、[Enter] を押してください : 100 割る整数を入力して、[Enter] を押してください : 13 9 $