/* * 20150605-02-QQQQ.c * * 自然数の階乗を返す関数 * * コンパイル : * cc -I../include -c 20150605-02-QQQQ.c * cc -o 20150605-02-QQQQ.exe 20150605-02-QQQQ.o * 実行 : * ./20150605-02-QQQQ.exe * */ #include <stdio.h> #include "s_print.h" /* s_print_int を利用するので.. */ /* * int factrial ( int n ) * int n : 階乗を計算する自然数 * 返り値 : n! ( n の階乗 ) */ int factrial ( int n ) { if ( n <= 0 ) { /* 0!, 負の数の階乗は、取り敢えず 1 にする */ return 1; /* 特に 「0! = 1」に注意 */ } else { /* n が正の時は、「n! = n * (n-1)!」となるので.. */ return n * factrial ( n - 1 ); /* 再帰呼び出し */ /* 自然数の階乗を返す関数 n! = n * (n-1) * ... * 2 * 1 曖昧なのでだめ n! = if ( n > 0 ) { 厳密な「再帰」の考えを使う方法 n * ((n-1)!) } else { 1 } */ } } /* * main */ int main( void ) { s_print_int ( 3 ); s_print_string ( " の階乗の値は " ); s_print_int ( factrial ( 3 ) ); s_print_string ( " になります。\n" ); s_print_int ( 5 ); s_print_string ( " の階乗の値は " ); s_print_int ( factrial ( 5 ) ); s_print_string ( " になります。\n" ); return 0; }
/* m,n 非負の整数とする m,n の最大公約数を d=(m,n) で表現する 数学的な性質 m >= n の時、(m,n) = (m-n,n) (@) (m,n) = (n.m) (m,0) = m 停止条件として利用 (0,n) = n 停止条件として利用 (m,n)=(n,(m%n)) (@) を繰り返し適用する ユークリッドの互除法は、上の性質を利用する (m,n) = if ( m == 0 ) { 停止条件 n } else if ( n == 0 ) { 停止条件 m } else if ( m >= n ) { (m-n,n) } else { (n-m,m) } */ /* * 20150605-03-QQQQ.c * * 二つの整数の最大公約数を返す * * コンパイル : * cc -I../include -c 20150605-03-QQQQ.c * cc -o 20150605-03-QQQQ.exe 20150605-03-QQQQ.o * 実行 : * ./20150605-03-QQQQ.exe * * */ #include <stdio.h> #include "s_print.h" /* s_print_int を利用するので.. */ /* * int euclid ( int a, int b ) * int a : 非負の整数 * int b : 非負の整数 * 返り値 : a と b の最大公約数を返す */ int euclid ( int a, int b ) { if ( b == 0 ) { /* 任意の数 a と 0 の最大公約数 (a,0) は a となる */ return a; } else { /* b が 0 でない時 (a,b) = (b,a%b) となる */ return euclid ( b, (a%b) ); /* b > 0 -> b > (a%b) 一番最初に a < b euclid ( a, b ) a % b -> a -> euclid ( b, a ) になる */ /* ** この部分を完成させなさい */ } } /* * main */ int main( void ) { s_print_int ( 12 ); s_print_string ( " と、 " ); s_print_int ( 18 ); s_print_string ( " の最大公約数は " ); s_print_int ( euclid( 12, 18 ) ); s_print_string ( " です。\n" ); s_print_int ( 1111 ); s_print_string ( " と、 " ); s_print_int ( 111111 ); s_print_string ( " の最大公約数は " ); s_print_int ( euclid( 1111, 111111 ) ); s_print_string ( " です。\n" ); return 0; }
/* * CDATE FILENAME * * 数当てを行う */ #include <stdio.h> #include "s_print.h" /* s_print_int を利用するので.. */ #include "s_input.h" /* s_input_int を利用するので.. */ /* * prompt * メッセージを出力し、キーボードから整数値を読み込んで、 * その値を返す関数 */ int prompt(void) { s_print_string ( "私が選んだ数を予想して入力してください : " ); return s_input_int(); } /* */ void game ( int input, int answer ) { if ( input == answer ) { /* 入力と答えが一致した */ s_print_string ( "お見事です。あたりました。\n" ); } else { if ( input > answer ) { /* 入力が、答えより大きい */ s_print_string ( "その数は大きすぎます。\n" ); } else { /* 入力が、答えより小さい */ s_print_string ( "その数は小さすぎます。\n" ); } /* 未だ、答えが、当っていないので、ゲームを続ける.. */ game ( prompt(), answer ); } } /* * main */ int main( void ) { s_print_string ( "乱数を初期化しますので、整数を一つ入力してください : " ); srand ( s_input_int() ); /* 乱数の初期化 */ s_print_string ( "私が考えた 1 〜 100 の数を予想して当ててみてください。\n" ); game ( prompt(), (rand()%100) + 1 ); return 0; }
#include <stdio.h> /* * 偶数奇数を判定して、答える */ void parity ( int number ) { if ( number % 2 == 0 ) { /* number を 2 割った余り ( A % B ... A を B 割った余り ) が 0 */ /* <-> number が偶数 */ printf ( "偶数\n" ); } else { /* 余りはおそらく 1 だろうが.. いずれにせよ .. */ printf ( "奇数\n" ); } } int main(int argc, char *argv[] ) { parity ( 2 ); /* 2 は、偶数なので、「偶数」と表示される */ parity ( 7 ); /* 7 は、奇数なので、「奇数」と表示される */ return 0; }
#include <stdio.h> /* 再起の考え方 「再起呼び出し」そのものは、 関数を定義するときに、その本体に、自分自身を呼び出す 単純に、自分を呼び出すと、とまらなくなる */ void infinity() { printf ( "Hello, World\n" ); infinity(); /* 何も考えずに、再起呼び出しをする */ } int main(int argc, char *argv[] ) { printf ( "はじめます。何か入力してください " ); getchar(); /* まつ */ infinity(); /* やってしまった... */ printf ( "もどってきました.. ?\n" ); return 0; }
#include <stdio.h> /* 再起の考え方 「再起呼び出し」そのものは、 関数を定義するときに、その本体に、自分自身を呼び出す 単純に、自分を呼び出すと、とまらなくなる 繰り返し回数を有限にするには、 続けるかどうかを判断する if 文と組み合わせる 「状態:引数」を持つ必要がある 「状態」は、必ず、終わりに「近づける」必要がある */ void finit( int times ) { /* 引数 times は、繰り返す回数(状態)を表現している */ if ( times == 0 ) { /* やめる条件 */ /* もう何もしない */ } else { /* まだ、続ける */ printf ( "Hello, World\n" ); finit( times - 1 ); /* 考えて、再起呼び出しをする */ } } int main(int argc, char *argv[] ) { printf ( "はじめます。何か入力してください " ); getchar(); /* まつ */ finit( 10 ); /* 安心して、呼べる */ printf ( "もどってきました.. ?\n" ); return 0; }
#include <stdio.h> /* 再起の考え方 「再起呼び出し」そのものは、 関数を定義するときに、その本体に、自分自身を呼び出す 単純に、自分を呼び出すと、とまらなくなる 繰り返し回数を有限にするには、 続けるかどうかを判断する if 文と組み合わせる 「状態:引数」を持つ必要がある 「状態」は、必ず、終わりに「近づける」必要がある */ void finit( int times ) { /* 引数 times は、繰り返す回数(状態)を表現している */ if ( times == 0 ) { /* やめる条件 */ /* もう何もしない */ } else { /* まだ、続ける */ printf ( "Hello, World\n" + times ); finit( times - 1 ); /* 考えて、再起呼び出しをする */ } } int main(int argc, char *argv[] ) { printf ( "はじめます。何か入力してください " ); getchar(); /* まつ */ finit( 10 ); /* 安心して、呼べる */ printf ( "もどってきました.. ?\n" ); return 0; }
#include <stdio.h> /* 再起の考え方 「再起呼び出し」そのものは、 関数を定義するときに、その本体に、自分自身を呼び出す 単純に、自分を呼び出すと、とまらなくなる 繰り返し回数を有限にするには、 続けるかどうかを判断する if 文と組み合わせる 「状態:引数」を持つ必要がある 「状態」は、必ず、終わりに「近づける」必要がある */ void finit( int times ) { /* 引数 times は、繰り返す回数(状態)を表現している */ if ( times == 0 ) { /* やめる条件 */ /* もう何もしない */ } else { /* まだ、続ける */ if ( times == 1 ) { /* times の値に基づいて色々 */ printf ( "こんにちわ\n" ); } else if ( times == 2 ) { printf ( "Hello\n" ); } else if ( times == 3 ) { printf ( "こんばんわ\n" ); } else if ( times == 4 ) { printf ( "Good bye\n" ); } else { if ( times % 2 == 0 ) { printf ( "ありがとう\n" ); } else { printf ( "ごちそうさま\n" ); } } finit( times - 1 ); /* 考えて、再起呼び出しをする */ } } int main(int argc, char *argv[] ) { printf ( "はじめます。何か入力してください " ); getchar(); /* まつ */ finit( 10 ); /* 安心して、呼べる */ printf ( "もどってきました.. ?\n" ); return 0; }
#include <stdio.h> /* 再起の考え方 「再起呼び出し」そのものは、 関数を定義するときに、その本体に、自分自身を呼び出す 単純に、自分を呼び出すと、とまらなくなる 繰り返し回数を有限にするには、 続けるかどうかを判断する if 文と組み合わせる 「状態:引数」を持つ必要がある 「状態」は、必ず、終わりに「近づける」必要がある */ /* finit の作り方(パターン) は、 times (非負の整数値を指定する) 回だけ、 (@) の行の命令を繰り返す */ void finit( int times ) { /* 引数 times は、繰り返す回数(状態)を表現している */ if ( times == 0 ) { /* やめる条件 */ /* もう何もしない */ } else { /* まだ、続ける */ /*printf ( "Hello, World\n" );*/ printf ( "こんにちわ、みなさん\n" ); /* (@) */ finit( times - 1 ); /* 考えて、再起呼び出しをする */ } } int main(int argc, char *argv[] ) { printf ( "はじめます。何か入力してください " ); getchar(); /* まつ */ finit( 10 ); /* 安心して、呼べる */ printf ( "もどってきました.. ?\n" ); return 0; }
#include <stdio.h> #include "s_print.h" /* 値を返す関数(先週新しくやった) 関数の前に void ではなく、値の型を書く 「return 式」で、値を計算する「式」を記述し、その 式の値が、関数の値になる */ /* 例 : 二つの整数値を引数として、取り その二つの整数値の「和」を値として返す関数 ! 「整数値の和」は、「整数値(int 型)」 */ int int_add(int a, int b) { return a + b; /* a と b の和を返す */ /* return の後ろには、「式」がかかれるが 実際に値して返るのは「式」の計算した値 が返る (式が返るわけではない) */ } int main(int argc, char *argv[] ) { printf ( "12 と 34 の和は " ); s_print_int ( int_add ( 12, 34 ) ); /* 関数の値は、式の中で利用することができる */ /* ! 関数の引数は、「式」を指定する */ printf ( " です\n" ); return 0; }
#include <stdio.h> int main(int argc, char *argv[] ) { /* 考えてみると... いきなり出力 -> 変化はない プログラムを作成した段階で、動作が確定している 入力によって、様々な場合に対する 処理(答え)を得たい プログラムの基本構造 入力 -> 処理 -> 出力 */ putchar ( getchar() - 'A' + 'a' ); /* ^^^^^^^ 入力 (一文字:大文字) ^^^^^^^^^^^^^^^^^^^^^^ 処理 (大文字を小文字) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 出力 */ putchar ( '\n' ); /* 改行 (出力) */ /* 入力が大文字以外だと、ちゃんと動かない -'A'+'a'が意味を持つのは、大文字の時のみ 本来なら、大文字か小文字かを判定して、処理をすべき <<入力>> 入力は、関数呼び出しをしているので、「直接」には、 「その値が、一度しか利用」できない 入力した、結果を関数の引数として渡す 関数の中では、その値が、変数に入っているので、 その変数を何度でも参照して、(入力された)情報を、 複数回、利用できる。 */ return 0; }
#include <stdio.h> /* 関数: 引数として、文字を入力とし、 それが大文字なら、小文字にして返す そうでなければ、そのまま返す関数 */ char to_lower ( char ch ) { if ( 'A' <= ch ) { if ( ch <= 'Z' ) { /* 大文字だった */ return ch - 'A' + 'a'; /* 小文字に変換して返す */ } else { } } else { } return ch; /* 元の文字をそのまま返す */ } int main(int argc, char *argv[] ) { putchar ( to_lower ( getchar() ) ); putchar ( '\n' ); return 0; }
#include <stdio.h> #include "s_print.h" /* 複数の入力を処理したい 三文字の数字を入力し、数字列が表す数に 1 を加えた数を表示する 例 : 123 -> 124 999 -> 1000 */ int main(int argc, char *argv[] ) { printf ( "数字を一文字入力する : " ); s_print_int ( getchar() ); /* 一文字入力して、整数値として出力 */ s_print_newline(); return 0; }
#include <stdio.h> #include "s_print.h" /* 複数の入力を処理したい 三文字の数字を入力し、数字列が表す数に 1 を加えた数を表示する 例 : 123 -> 124 999 -> 1000 */ int main(int argc, char *argv[] ) { printf ( "数字を一文字入力する : " ); s_print_int ( getchar() - '0' ); /* 一文字入力して、整数値として出力 */ /* n の数字に対応する数値 n が得られる */ s_print_newline(); return 0; }
#include <stdio.h> #include "s_print.h" /* 複数の入力を処理したい 三文字の数字を入力し、数字列が表す数に 1 を加えた数を表示する 例 : 123 -> 124 999 -> 1000 */ int main(int argc, char *argv[] ) { printf ( "数字を一文字入力する : " ); s_print_int ( getchar() - '0' + 1 ); /* 一文字入力して、整数値として出力 */ /* n の数字に対応する数値 n が得られる */ s_print_newline(); return 0; }
#include <stdio.h> #include "s_print.h" /* 複数の入力を処理したい 三文字の数字を入力し、数字列が表す数に 1 を加えた数を表示する 例 : 123 -> 124 999 -> 1000 */ int main(int argc, char *argv[] ) { printf ( "数字を三文字入力する : " ); s_print_int (((getchar() - '0')*100 + (getchar() - '0') * 10 + getchar() - '0') + 1 ); /* 「三文字」という入力の長さがわかっているからできる */ /* 長さがわからない 何回読むかも分からない 何回 getchar() を呼ぶかもわからない プログラムの命令の実行回数が変化する 再帰を利用すればよい */ s_print_newline(); return 0; }
#include <stdio.h> #include "s_print.h" /* 数字列を入力する 最後に改行をいれることにより、数字列も終わると考える 数字列をキーボードから入力して、その数字列が表す、 整数値を返す関数を考える "123\n" -> 123 '1' 続きがあるかもしれない。 すぐに、\n くるかもしれない とりあえず、ここまでの結果を num にいれる num <- 1 num <- ch - '0' '2' 続きがあるかもしれない。 すぐに、\n くるかもしれない とりあえず、ここまでの結果を num にいれる num <- 12 ... 1 * 10 + 2 num <- num * 10 + ch - '0' */ int input_int ( char ch, int num ) { /* 入力した結果を何度も利用するので、 先読みをする */ if ( ch == '\n' ) { return num; /* ch == '\n' num が結果 */ } else { return input_int ( getchar(), num * 10 + ch - '0' ); } } int main(int argc, char *argv[] ) { s_print_string ( "数字列を入力し、最後に[Enter]する : " ); s_print_int ( input_int( getchar(), 0 ) ); s_print_newline(); return 0; }
#include <stdio.h> #include <stdlib.h> /* rand 関数を利用するので、その宣言を読み込む */ #include "s_print.h" #include "s_input.h" /* rand() 呼び出すたびに、異なる数値を返す「乱数関数」である。 これを利用して... ゲームを作ったり シミュレーションを行ったりする [注意] ただし、毎回、同じ数列なので、それがいやなら、 srand を使って、乱数列を変更すればよい */ int main(int argc, char *argv[] ) { s_print_string ( "何か数値を入力してください(乱数初期化に使います) : " ); srand ( s_input_int() ); /* 入力した数値で、乱数を初期化 */ /* よくあるのは、時刻を利用する方法 */ s_print_int ( rand() ); /* 同じことを三回してるだけだが... */ s_print_newline(); s_print_int ( rand() ); s_print_newline(); s_print_int ( rand() ); s_print_newline(); return 0; }
Download : 20160701-01.c ( utf8 版 )
/* * CDATE FILENAME * * 数当てを行う */ #include <stdio.h> #include "s_print.h" /* s_print_int を利用するので.. */ #include "s_input.h" /* s_input_int を利用するので.. */ /* * prompt * メッセージを出力し、キーボードから整数値を読み込んで、 * その値を返す関数 */ int prompt(void) { s_print_string ( "私が選んだ数を予想して入力してください : " ); return s_input_int(); } /* */ void game ( int input, int answer ) { if ( input == answer ) { /* 入力と答えが一致した */ s_print_string ( "お見事です。あたりました。\n" ); } else { if ( input > answer ) { /* 入力が、答えより大きい */ /* ** この部分を完成させなさい */ } else { /* 入力が、答えより小さい */ s_print_string ( "その数は小さすぎます。\n" ); } /* 未だ、答えが、当っていないので、ゲームを続ける.. */ /* ** この部分を完成させなさい */ } } /* * main */ int main( void ) { s_print_string ( "私が考えた 1 〜 100 数を予想して当ててみてください。\n" ); game ( prompt(), (rand()%100) + 1 ); return 0; }
50 75 83 90 85 84
$ ./20160701-01-QQQQ.exe 私が考えた 1 〜 100 数を予想して当ててみてください。 私が選んだ数を予想して入力してください : 50 その数は小さすぎます。 私が選んだ数を予想して入力してください : 75 その数は小さすぎます。 私が選んだ数を予想して入力してください : 83 その数は小さすぎます。 私が選んだ数を予想して入力してください : 90 その数は大きすぎます。 私が選んだ数を予想して入力してください : 85 その数は大きすぎます。 私が選んだ数を予想して入力してください : 84 お見事です。あたりました。 $
Download : 20160701-02.c ( utf8 版 )
/* * CDATE FILENAME * * 与えられた自然数の素因数を出力する * * 12 は.. * * * * * * */ #include <stdio.h> #include "s_print.h" /* s_print_int を利用するので.. */ /* * void print_prime_factor_sequence ( int n, int p ) * 機能 : p 以上の n の素因数を小さい順に並べで表示する * 条件 : n には p 未満の素因数を含まれていないものとする * int n : p 未満の素因数を含まれていない自然数 * 返り値 : なし */ void print_prime_factor_sequence ( int n, int p ) { if ( p > n ) { /* もう n には p 以上の素因数を含まない */ /* 何もしなくてよい */ /* 本来、ここにくるのは n = 1 の時だが、念の為 */ } else if ( n % p == 0 ) { /* n が p を素因数として含む */ s_print_char ( ' ' ); /* 隙間を空け */ s_print_int ( p ); /* 素因数を表示し */ /* もう一度 p の要素があるかもしれないので、そこから試す [再帰] */ /* ** この部分を完成させなさい */ } else { /* n が p を素因数として含まない */ /* 本来は p の次の素数を試すべきだが.. */ /* その代りに p + 1 を試す (のは無駄だが、正く動く) [再帰] */ /* ** この部分を完成させなさい */ } } /* * void print_prime_factor_of ( int n ) * 機能 : n の素因数を出力する * int n : 素因数を表示したい自然数 * 返り値 : なし */ void print_prime_factor_of ( int n ) { if ( n < 1 ) { /* 与えらた数が自然数ではない */ s_print_int ( n ); s_print_string ( "は、自然数ではありません\n" ); } else if ( n == 1 ) { /* 与えられた数が 1 の場合 */ s_print_int ( n ); s_print_string ( "の素因数はありません\n" ); } else { s_print_int ( n ); s_print_string ( "の素因数分解は" ); /* ** この部分を完成させなさい */ s_print_string ( " となります。\n" ); } } /* * main */ int main( void ) { print_prime_factor_of ( 12 ); return 0; }
$ ./20160701-02-QQQQ.exe 12の素因数分解は 2 2 3 となります。 $