#include <stdio.h> /* あること(命令)を繰り返したい => 「Hello, World」を出力 繰り返し : 同じ事を k 回数行う => k をどうするか ? 例: 繰り返す回数を 3 とした場合... ?? ここでは、 1. 文字列には長さがある 例 : "abc" => 長さ 3 2. (原理は不明だが..) 文字列に +1 すると、文字列の長さは 短くなる 3. 文字列を、短くしてゆく(+1 する)と、最後に "" 空文字列になる => 条件判定で、判断(チェック)できる という文字列の性質を利用し 繰り返し回数を文字列(の長さ)で表現する 例 : 3 という回数を示すのに、"abc" 長さ 3 の文字列を利用する times_hello ( "abc" ); => 3 回、「Hello, World」を表示する */ void times_hello (char *n ) { /* 引数 n は、文字列だが、中身はどうでもよくて、長さだけが重要 */ /* 繰り返しのパターン[再帰] */ if ( !strcmp ( n, "" ) ) { /* 空文字列 : 長さが 0 ということ... */ /* 繰り返しの回数が、0 なので、なにもしないで「終わり」にしてよい */ } else { /* 少なくても、一度は、Hello World を出す必要がある */ /* 繰り返したい命令 */ printf ( "Hello, World\n" ); /* 残りは ? ( やりたい目的の回数 - 1 回 )*/ times_hello ( n + 1 ); /* 残りは、再帰呼び出しにする */ /* ポイントは、引数の文字列に +1 する事により、 長さを 1 つだけ、短くする(繰り返し回数が 1 減る ) */ } } int main(void) { printf ( "3 回数出力\n" ); times_hello ( "123" ); printf ( "10 回数出力\n" ); times_hello ( "1234567890" ); return 0; }
#include <stdio.h> int main(void) { putchar ( 'A' ); /* 画面に「A」という文字を出力する */ /* 「文字」を出すので「'A'」という形 */ /* 「文字」を扱うので putchar を利用している */ /* cf. printf ( "A" ); */ putchar ( '\n' ); /* 「\n」は「改行」を表す「文字」 */ return 0; }
#include <stdio.h> int main(void) { putchar ( getchar() ); /* キーボードから一文字読み込む(getchar) その文字を画面に出す(putchar) */ putchar ( '\n' ); /* 「\n」は「改行」を表す「文字」 */ return 0; }
#include <stdio.h> /* 三文字入力して、三文字出力する */ int main(void) { putchar ( getchar() ); putchar ( getchar() ); putchar ( getchar() ); /* 関数合成を行っている事に注意 */ /* 順接のもう一つの形 */ /* getchar() => putchar() : 二つの関数を順序付けている */ putchar ( '\n' ); /* 「\n」は「改行」を表す「文字」 */ return 0; }
#include <stdio.h> /* 入力が、毎回、1 文字 + 改行になる事を想定して、画面に出す */ int main(void) { putchar ( getchar() ); /* 入力された文字列 */ getchar(); /* 次に「改行」が来るはずだが、読み飛ばす */ putchar ( '?' ); putchar ( '\n' ); putchar ( getchar() ); /* 入力された文字列 */ getchar(); /* 次に「改行」が来るはずだが、読み飛ばす */ putchar ( '?' ); putchar ( '\n' ); putchar ( getchar() ); /* 入力された文字列 */ getchar(); /* 次に「改行」が来るはずだが、読み飛ばす */ putchar ( '?' ); putchar ( '\n' ); putchar ( '\n' ); /* 「\n」は「改行」を表す「文字」 */ return 0; }
#include <stdio.h> /* 目的 Turtle Grapics をしたい プログラム作成上の注意 #include "s_turtle.h" を冒頭にいれる プログラムを実行する場合は、 make test BASE=ファイルのベース名とする 例: p-006.c を実行するには、 make test BASE=p-006 とする。 # getchar() が最後にあるので、[Enter] キーを # 押さないと、プログラムが終了しない事に注意 */ #include "s_turtle.h" /* turtle graphics をする場合の追加のおまじない */ /* 命令 Turtle Graphics で利用できる命令 s_turtle_move(); : 現在の位置に足跡を残し、現在の方向に一歩進みます s_turtle_jump(); : 現在の位置に足跡を残さず、現在の方向に一歩進みます s_turtle_turn(); : 現在の方向を時計回りに 45 度変更します s_turtle_stop(); : 亀プログラムの終了 (「return 0;」の直前に実行) */ int main(void) { /* Turtle Graphics の命令を書く */ s_turtle_move(); /* 亀への命令をする */ /* 亀は、今いる場所に、足跡を残し、 自分が向いている方向に一歩進む */ /* 結果的に、画面に「足跡」が一歩(一点)だけ残る */ getchar(); /* いきなり終了せず、いったん改行を待つ */ s_turtle_stop(); return 0; }
#include <stdio.h> #include "s_turtle.h" int main(void) { /* Turtle Graphics の命令を書く */ s_turtle_move(); /* 10歩,歩きながら、足跡を残す */ s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_turn(); /* 亀の向きを 45 度変える */ s_turtle_turn(); /* 亀の向きを 45 度変える */ s_turtle_move(); /* 10歩,歩きながら、足跡を残す */ s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); getchar(); s_turtle_stop(); return 0; }
#include <stdio.h> #include "s_turtle.h" /* 一辺の長さが 10 である正方形を書くプログラム */ /* +---+ | | 一辺の長さが 10 +---+ 1) 10 回 move すれば、長さ 10 直線がかける 2) 2 回 turn すれば、90 度(直角)の向きがかえられる 3) 正方形は、直角に交わる 4 辺からなる */ int main(void) { /* Turtle Graphics の命令を書く */ /* 左辺 */ s_turtle_move(); /* 10歩,歩きながら、足跡を残す */ s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_turn(); /* 亀の向きを 45 度変える */ s_turtle_turn(); /* 亀の向きを 45 度変える */ /* 上辺 */ s_turtle_move(); /* 10歩,歩きながら、足跡を残す */ s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_turn(); /* 亀の向きを 45 度変える */ s_turtle_turn(); /* 亀の向きを 45 度変える */ /* 右辺 */ s_turtle_move(); /* 10歩,歩きながら、足跡を残す */ s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_turn(); /* 亀の向きを 45 度変える */ s_turtle_turn(); /* 亀の向きを 45 度変える */ /* 下辺 */ s_turtle_move(); /* 10歩,歩きながら、足跡を残す */ s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); getchar(); s_turtle_stop(); return 0; }
#include <stdio.h> #include "s_turtle.h" /* 一辺の長さが 10 である正方形を書くプログラム */ /* 関数を利用して、プログラムを整理しよう.. */ /* move_ten() 10 歩進む */ void move_ten(void) { s_turtle_move(); /* 10歩,歩きながら、足跡を残す */ s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); s_turtle_move(); } /* turn_R() 90 度向き変える */ void turn_R(void) { s_turtle_turn(); /* 亀の向きを 45 度変える */ s_turtle_turn(); /* 亀の向きを 45 度変える */ } int main(void) { /* Turtle Graphics の命令を書く */ /* 左辺 */ move_ten(); turn_R(); /* 上辺 */ move_ten(); turn_R(); /* 右辺 */ move_ten(); turn_R(); /* 下辺 */ move_ten(); getchar(); s_turtle_stop(); return 0; }
#include <stdio.h> #include "s_turtle.h" /* 一辺の長さが 10 である正方形を書くプログラム */ /* 関数を利用して、プログラムを整理しよう.. */ /* move_n n 歩 move する(n は引数で、繰り返し回数を指定する ) => 引数に文字列を指定して、その長さだけ繰り返す */ void move_n(char *times) { if ( !strcmp ( times, "" ) ) { } else { s_turtle_move(); move_n ( times + 1 ); } } /* move_ten() 10 歩進む */ void move_ten(void) { move_n ( "1234567890" ); } /* turn_R() 90 度向き変える */ void turn_R(void) { s_turtle_turn(); /* 亀の向きを 45 度変える */ s_turtle_turn(); /* 亀の向きを 45 度変える */ } /* 辺の長さが 10 を書く rect_ten */ void rect_ten(void) { /* 左辺 */ move_ten(); turn_R(); /* 上辺 */ move_ten(); turn_R(); /* 右辺 */ move_ten(); turn_R(); /* 下辺 */ move_ten(); } int main(void) { /* Turtle Graphics の命令を書く */ rect_ten(); /* 辺の長さが 10 の正方形 */ /* さらに、30 の正方形も * getchar(); s_turtle_stop(); return 0; }
#include <stdio.h> #include "s_turtle.h" /* 一辺の長さが n である正方形を書くプログラム */ /* move_n n 歩 move する(n は引数で、繰り返し回数を指定する ) => 引数に文字列を指定して、その長さだけ繰り返す */ void move_n(char *times) { if ( !strcmp ( times, "" ) ) { } else { s_turtle_move(); move_n ( times + 1 ); } } void turn_n(char *times) { if ( !strcmp ( times, "" ) ) { } else { s_turtle_turn(); turn_n ( times + 1 ); } } /* turn_R() 90 度向き変える */ void turn_R(void) { turn_n ( "01" ); } /* 辺の長さが n の正方形を書く rect_n */ void rect_n(char *length) { /* 左辺 */ move_n(length); turn_R(); /* 上辺 */ move_n(length); turn_R(); /* 右辺 */ move_n(length); turn_R(); /* 下辺 */ move_n(length); turn_R(); } int main(void) { /* Turtle Graphics の命令を書く */ rect_n("1234567890" ); /* 辺の長さが 10 の正方形 */ /* 外側の正方形の書き出し位置と向きを調整すればよい */ /* 今いるところから、左下に 10 歩のところにゆけばよい */ turn_n ( "12345" ); /* 亀の向きを右下に向ける */ move_n ( "1234567890" ); /* 10 歩歩く */ turn_n ( "123" ); /* 亀の向きを上に戻す */ /* さらに、30 の正方形も */ rect_n( "123456789012345678901234567890" ); /* 辺の長さが 10 の正方形 */ getchar(); s_turtle_stop(); return 0; }
BASE=p-001 all : ${BASE}.exe ${BASE}.exe : ${BASE}.o cc -o ${BASE}.exe ${BASE}.o ${BASE}.o : ${BASE}.c cc -c ${BASE}.c test : ${BASE}.exe ./${BASE}.exe
[復習] 前回、再帰呼び出しを利用した、繰り返し 繰り返しのパターン k 回、繰り返したい場合 長さ k の文字列 n を引数として指定して、再帰呼び出しをする 1. 関数の名前決める 2. 次のひな型を作る void 関数名 ( char *n ) { if ( !strcmp ( n, "" ) ) { /* なにもしない */ } else { /* 繰り返したい命令 : 再帰とは無関係でよい */ /* 「ここ」*/ /* 再帰 */ 関数名 ( n + 1 ); } } 3. 繰り返したい命令を「ここ」のところに挿入 4. 繰り返しを実行する場合 関数名 ( 繰り返す回数の長さ文字列 ); [今日の目標] 「繰り返し」に慣れる 命令が「文字列のプリント」だけではつまらないので、 絵を描く事を考える 文字 C 言語では、「文字」を、表すためには、 「'」 + その文字を表す文字(一字) + 「'」 例 : 「'A'」は、「A」という文字を表す C 言語の表現 特殊な例として '\' で始まる二文字で一文字を表す場合もある 例 : '\n' => 改行一文字 '\0' => NUL 文字(空文字) が実は、文字列の最後にある '\\' => 「\」という文字を表す # Windows では「\(円マーク)」 # Ubuntu では「\(バックスラッシュ)」になる cf. 「"A"」は、「A」という文字を一つ含む文字列 文字を出力するときには、 putchar 関数を利用する 例 : 「A」という文字を出力する場合は、 putchar ( 'A' ); とする。 文字を入力するときには、 getchar() 関数が利用できる getchar() を呼び出すと、キーボードから、一文字 読み込み、その一文字が、「関数の値」となる 例 : キーボードから、一文字入力し、それを画面に出すには、 putchar ( getchar() ); とする。 putchar の引数は、「文字」でなければならないが、 getchar が返す値が「文字」なので、うまくゆく # 入力は、[Enter] キーが押されるまで、待つ仕組みになっている # 待つ事を目的として getcharを使う
BASE=p-001 all : ${BASE}.exe ${BASE}.exe : ${BASE}.o cc -o ${BASE}.exe ${BASE}.o ${BASE}.o : ${BASE}.c cc -c ${BASE}.c test : ${BASE}.exe ./${BASE}.exe
Download : 20180601-01.c
/* * 20180601-01-QQQQ.c * 与えられた文字列の文字を二度ずつ出力する関数を作成する */ #include <stdio.h> #include <strings.h> /* * double_print * 与えられた文字列(message)の文字を二度ずつ出力する */ void double_print ( char *message ) { if ( !strcmp ( message, "" ) ) { /* 空文字列だった */ /* なにもする必要はない */ } else { putchar ( *message ); /* 取り敢えず、一つ分は出す */ /* ** この部分を完成させなさい */ double_print ( message + 1 ); /* 再帰呼出しをする */ } } /* * main */ int main ( void ) { double_print ( "abc" ); printf ( "\n" ); double_print ( "1234567" ); printf ( "\n" ); return 0; }
$ ./20180601-01-QQQQ.exe aabbcc 11223344556677 $
Download : 20180601-02.c
/* * 20180601-02-QQQQ.c * 与えられた文字列の文字を逆順に出力する関数を作る */ #include <stdio.h> #include <strings.h> /* * reverse_print * 与えられた文字列(message)の文字を逆順に出力する */ void reverse_print ( char *message ) { if ( !strcmp ( message, "" ) ) { /* 空文字列だった */ /* なにもする必要はない */ } else { /* ここで再帰呼出しを行うのだが... */ /* ** この部分を完成させなさい */ } } /* * main */ int main ( void ) { reverse_print ( "abc" ); printf ( "\n" ); reverse_print ( "1234567" ); printf ( "\n" ); return 0; }
$ ./20180601-02-QQQQ.exe cba 7654321 $