/* * 20180601-01-QQQQ.c * 与えられた文字列の文字を二度ずつ出力する関数を作成する */ #include <stdio.h> #include <strings.h> /* * double_print * 与えられた文字列(message)の文字を二度ずつ出力する * * [考え方:簡単な具体例] * double_print ( "" ); * "" を出す (何もしなくてもよい) * double_print ( "abc" ); * aabbcc * double_print ( "abcdef" ); * ^^^ * aabbccddeeff * ^^^^^^====== * 具体的な例で考えて、例での規則性を見つける * 先頭の部分が同じ * duble_print ( "abcdef" ) * duble_print ( "abc" ) * aabbcc * duble_print ( "def" ) * ddeeff * 特に、先頭の文字だけに着目すれば、 * duble_print ( "abcdef" ) * 'a' を二度プリントして * 残りは、double_print ( "bcdef" ) とすればよい * 再帰呼び出しが利用できる * duble_print ( message ) * message の先頭を二度プリントして * *message を二度 putchar * 残りは、double_print ( message + 1 ) とすればよい */ 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-02-QQQQ.c * 与えられた文字列の文字を逆順に出力する関数を作る */ #include <stdio.h> #include <strings.h> /* * reverse_print * 与えられた文字列(message)の文字を逆順に出力する */ void reverse_print ( char *message ) { if ( !strcmp ( message, "" ) ) { /* 空文字列だった */ /* なにもする必要はない */ } else { /* ここで再帰呼出しを行うのだが... */ putchar ( *message ); reverse_print ( message + 1 ); /* とすると、正順に出力されてしまう .. */ /* 目的は、逆順にすることなので、.. */ /* そのためには、この順ではなく... */ /* 再帰呼び出しを利用した関数定義で、 繰り返したい命令の順序を逆順にするには、 繰り返し命令: 再帰の順ではなく、 これを交換した、 再帰;繰り返し命令 の形にすればよい */ } } /* * main */ int main ( void ) { reverse_print ( "abc" ); printf ( "\n" ); reverse_print ( "1234567" ); printf ( "\n" ); return 0; }
/* * 2018/06/08 hanoi3.c * 高さ 3 のハノイの塔を解く */ #include <stdio.h> /* * ハノイプログラムには、s_hanoi.h が必要 */ #include "s_hanoi.h" /* * ハノイの塔 プログラム */ int main ( void ) { /* * 最初は "1" に全ての円盤が置いてある */ /* * ハノイで、できること * s_hanoi_init() : ハノイプログラムの開始 : 最初に一度だけ呼び出す * s_hanoi_size ( char *discs ) : ハノイの塔の高さを設定する * s_hanoi_move ( char *from, char *to ) : from にある円盤を to に移す * s_hanoi_clear () : 最初の状態に戻す * s_hanoi_stop() : ハノイプログラムの終了 : return 0 の前に呼び出す */ s_hanoi_init(); s_hanoi_size ( "***" ); // 高さを 3 に設定 putchar ( '>' ); putchar ( getchar() ); s_hanoi_move ( "1", "3" ); /* [1] が 1 から 3 に移動 */ putchar ( '>' ); putchar ( getchar() ); s_hanoi_move ( "1", "2" ); /* [2] が 1 から 2 に移動 */ putchar ( '>' ); putchar ( getchar() ); s_hanoi_stop(); return 0; }
#include <stdio.h> /* * n 回、プリントする (nprint) */ void nprint(char *ntimes) { if ( !strcmp ( ntimes, "" ) ) { /* ntimes が 空文字かどうか */ /* do nothing */ } else { /* 繰り返したい命令 */ printf ( "Hello, World\n" ); nprint ( ntimes + 1 ); } } int main(void) { printf ( "三回\n" ); nprint ( "***" ); printf ( "五回\n" ); nprint ( "12345" ); return 0; }
#include <stdio.h> /* * n 回、プリントする (nprint) */ void nprint(char *ntimes, char *message) { if ( !strcmp ( ntimes, "" ) ) { /* do nothing */ } else { /* 繰り返したい命令 */ printf ( message ); nprint ( ntimes + 1, message ); } } int main(void) { printf ( "三回\n" ); nprint ( "***", "Hello, World\n" ); printf ( "五回\n" ); nprint ( "12345", "みなさん、こんにちわ\n" ); return 0; }
#include <stdio.h> /* * n 回、プリントする (nprint) */ void nprint(char *ntimes, char *message) { if ( !strcmp ( ntimes, "" ) ) { /* do nothing */ } else { /* 繰り返したい命令 */ printf ( message ); nprint ( ntimes + 1, message + 1); } } int main(void) { printf ( "三回\n" ); nprint ( "***", "Hello, World\n" ); printf ( "五回\n" ); nprint ( "12345", "みなさん、こんにちわ\n" ); return 0; }
#include <stdio.h> int main(void) { printf ( "文字列 \"abc\" の先頭の文字は「" ); putchar ( *"abc" ); /* 文字列 "abc" の先頭の文字は 'a' */ printf ( "」です。\n" ); return 0; }
#include <stdio.h> int main(void) { printf ( "文字列 \"abc\" + 1 の先頭の文字は「" ); putchar ( *("abc"+1) ); /* 文字列 "abc" の先頭の次の文字は 'b' */ printf ( "」です。\n" ); return 0; }
#include <stdio.h> int main(void) { printf ( "文字列 \"abc\" + 1 の先頭の文字は「" ); putchar ( "abc"[1] ); /* 文字列 "abc" の先頭の次の文字は 'b' */ /* "abc"[1] => *("abc"+1) と同じ */ printf ( "」です。\n" ); return 0; }
#include <stdio.h> /* * n 回、プリントする (nprint) */ void nprint(char *ntimes) { if ( *ntimes == '\0' ) { /* ntimes が 空文字列かどうか */ /* もし、ntimes が空文字 "" なら *"" は nul 文字 '\0' (EOS) になる */ /* do nothing */ } else { /* 繰り返したい命令 */ printf ( "Hello, World\n" ); nprint ( ntimes + 1 ); } } int main(void) { printf ( "三回\n" ); nprint ( "***" ); printf ( "五回\n" ); nprint ( "12345" ); return 0; }
#include <stdio.h> /* * myprintf を作る * myprintf ( "abc" ); * => abc と出力 * Version 1 : printf をそのまま利用 */ void myprintf (char *string) { printf ( string ); /* printf をそのまま利用する */ } int main(void) { myprintf ( "Hello, World\n" ); myprintf ( "皆さん、こんにちは\n" ); return 0; }
#include <stdio.h> /* * myprintf を作る * myprintf ( "abc" ); * => abc と出力 * Version 2 : printf を利用せず、putchar を利用する * * myprintf ( "abc" ); * => abc * => a bc * => putchar ( 'a' ); myprinf ( "bc" ); * => putchar ( *"abc" ); myprinf ( "abc" + 1 ); * myprintf ( string ); * => putchar ( *string ) ; myprintf ( string + 1 ); * 後は、string が "" の時だけ特別扱い */ void myprintf (char *string) { if ( *string == '\0' ) { } else { putchar ( *string ); myprintf ( string + 1 ); } } int main(void) { myprintf ( "Hello, World\n" ); myprintf ( "皆さん、こんにちは\n" ); return 0; }
#include <stdio.h> /* * myprintf を作る * version 3 * もし、文中に '*' がでたら、そこだけ、(^o^)を出す * それ以外は、そのまま出す * */ void myprintf (char *string) { if ( *string == '\0' ) { } else { if ( *string == '*' ) { /* その文字が '*' なら */ printf ( "(^o^)" ); } else { putchar ( *string ); } myprintf ( string + 1 ); } } int main(void) { printf ( "Hello, World\n" ); myprintf ( "Hello, World\n" ); printf ( "Hello, World *\n" ); myprintf ( "Hello, World *\n" ); return 0; }
#include <stdio.h> /* * myprintf を作る * version 3 * もし、文中に '*' がでたら、そこだけ、(^o^)を出す * それ以外は、そのまま出す * */ #define EOS '\0' /* '\0' に EOS という名前を付ける */ /* マクロ EOS を定義し、その値を '\0' とした */ /* EOS = 「End Of String」 */ /* 以下、EOS が現れると、'\0' に置き換える */ #define SMAILE '*' void myprintf (char *string) { if ( *string == EOS ) { } else { if ( *string == SMAILE ) { printf ( "(^o^)" ); } else { putchar ( *string ); } myprintf ( string + 1 ); } } int main(void) { printf ( "Hello, World\n" ); myprintf ( "Hello, World\n" ); printf ( "Hello, World *\n" ); myprintf ( "Hello, World *\n" ); return 0; }
#include <stdio.h> /* * n 回、プリントする (nprint) * * nprint ( "abc" ); * => * Hello, World * Hello, World * Hello, World * => * Hello, World * * Hello, World * Hello, World * => * printf ( "Hello, World\n" ): * nprint ( "bc" ); * * nprint ( "abc" ); * => * Hello, World * Hello, World * Hello, World * => * Hello, World * Hello, World * * Hello, World * => * nprint ( "bc" ); * printf ( "Hello, World\n" ): */ void nprint(char *ntimes) { if ( !strcmp ( ntimes, "" ) ) { /* ntimes が 空文字かどうか */ /* do nothing */ } else { nprint ( ntimes + 1 ); /* 繰り返したい命令 */ printf ( "Hello, World\n" ); } } int main(void) { printf ( "三回\n" ); nprint ( "***" ); printf ( "五回\n" ); nprint ( "12345" ); return 0; }
#include <stdio.h> /* * n 回、プリントする (nprint) * * nprint ( "***" ) * => * *** * ** * * * => * *** * * ** * * * => * printf ( "***" ); * printf ( "\n" ); * nprint ( "**" ); * [一般化] * nprint ( message ) * => * printf ( message ); * printf ( "\n" ); * nprint ( message + 1 ); */ #define EOS '\0' void nprint(char *ntimes) { if ( *ntimes == EOS ) { /* ntimes が 空文字かどうか */ /* do nothing */ } else { /* 繰り返したい命令 */ printf ( ntimes ); printf ( "\n" ); /* putchar ( '\n' ) */ nprint ( ntimes + 1 ); } } int main(void) { printf ( "三回\n" ); nprint ( "***" ); printf ( "五回\n" ); nprint ( "12345" ); return 0; }
#include <stdio.h> /* * n 回、プリントする (nprint) * * nprint ( "***" ) * => * nprint ( "***" + 1 ); * * printf ( "***" ); * printf ( "\n" ); * => * nprint ( "**" ); * * printf ( "***" ); * printf ( "\n" ); * => * nprint ( "**" + 1 ); * * printf ( "**" ); * printf ( "\n\" ); * * printf ( "***" ); * printf ( "\n" ); * => .. => * * * ** * *** */ #define EOS '\0' void nprint(char *ntimes) { if ( *ntimes == EOS ) { /* ntimes が 空文字かどうか */ /* do nothing */ } else { nprint ( ntimes + 1 ); /* 繰り返したい命令 */ printf ( ntimes ); printf ( "\n" ); /* putchar ( '\n' ) */ } } int main(void) { printf ( "三回\n" ); nprint ( "***" ); printf ( "五回\n" ); nprint ( "12345" ); return 0; }
[今日の内容] 前回、再帰を利用した、「繰り返し」を学んだ => 繰り返しができると、いろいろな事ができる n 回繰り返す 前回:文字を学んだ 文字と文字列の関係 [人間の意識] "ABC" : 長さ 3 の文字列で、その中身は、 'A', 'B', 'C' という三つの文字からなる [C 言語では、どう表現されるか ?] 文字列の先頭に「*」を付けると、先頭の文字が取り出せる 例: *"abc" <=> 'a' "abc" + 1 => "bc" *("abc"+1) => *("bc") => 'b' 「*」を利用すると、「文字列」から「文字」が取り出せる *"abc" => "abc" の 0 番目(先頭)の文字 *"abc" => *("abc"+0) *("abc"+1) => "abc" の 1 番目(先頭の次)の文字 *("abc"+n) => "abc" の n 番目の文字 "abc"[n] で表現してもよい "abc"[n] => *("abc"+n) 文字列 "abc" の 0 番目の文字は, "abc"[0] で表現 "" 空文字列(長さ 0 の文字列) *"" => '\0' (空文字 : 文字列の終わりを表す特別な文字) "abc" = { 'a', 'b', 'c', '\0' } "" = { '\0' } # '\0' nul 文字、空文字、End of String (EOS) 文字列を表す変数を str とするときに *str == '\0' は、 !strcmp ( str, "" ) より一般に文字列の比較は、!strcmp を使った と同じ、「条件」を表す 特に、「文字」を比較するのに「==」が使われる !! 「=」を使ってはいけない 「==」を利用すれば、「文字」の比較が可能 「==」を学んだので、文字に着目して条件分岐が可能になった 既存の仕組みを、自分で再現する事により、それを変更して、機能を追加できる #define を利用して、文字に名前が付けられる 以下、名前を参照するだけで、文字に置き換わる この #define で定義された名前を「マクロ」と呼ぶ 課題 20180601-01 与えられた文字列の文字を二度ずつ出力する関数を作成する double_print ( "abc" ); => aabbcc 課題 20180601-02 与えられた文字列の文字を逆順に出力する関数を作成する reverse_print ( "abc" ); => cba => cb a => reverse_print ( "bc" ); putchar ( 'a' ) => reverse_print ( "abc" + 1 ); putchar ( *"abc" ) [一般化] reverse_print ( message ); => reverse_print ( message + 1 ); putchar ( *message );
Download : 20180608-01.c
/* * 20180608-01-QQQQ.c * 高さ3 のハノイの塔を手動で解く */ #include <stdio.h> /* * ハノイプログラムには、s_hanoi.h が必要 */ #include "s_hanoi.h" /* * ハノイの塔 プログラム */ int main ( void ) { /* * 最初は "1" に全ての円盤が置いてある * これを "2" に全ての円盤を移動する */ /* * ハノイで、できること * s_hanoi_init() : ハノイプログラムの開始 : 最初に一度だけ呼び出す * s_hanoi_size ( char *discs ) : ハノイの塔の高さを設定する * s_hanoi_move ( char *from, char *to ) : from にある円盤を to に移す * s_hanoi_clear () : 最初の状態に戻す * s_hanoi_stop() : ハノイ塔プログラムの終了 : return 0 の前に呼び出す */ s_hanoi_init(); /* ハノイの塔のプログラムの初期変化 */ /* s_hanoi_set ( char *discs ) を呼ばなければ、高さは 3 */ printf ( "これから解答を開始します。[Enter] キーを押してください\n" ); putchar ( '>' ); putchar ( getchar() ); /* 開始前に、一旦停止 */ /* 解答開始 */ /* 高さが、具体的な小さい数(3)で指定されているので、 解答手順を実際に書き下すだけ */ s_hanoi_move ( "1", "2" ); /* 1 から 2 に、(大きさ 1 の)円盤を移動 */ s_hanoi_move ( "1", "3" ); /* 1 から 3 に、(大きさ 2 の)円盤を移動 */ /* ** この部分を完成させなさい */ s_hanoi_move ( "1", "2" ); /* 1 から 2 に、(大きさ 3 の)円盤を移動 */ s_hanoi_move ( "3", "1" ); /* 3 から 1 に、(大きさ 1 の)円盤を移動 */ /* ** この部分を完成させなさい */ s_hanoi_move ( "1", "2" ); /* 1 から 2 に、(大きさ 1 の)円盤を移動 */ /* 解答終了 */ printf ( "プログラムを終了するには [Enter] キーを押してください\n" ); putchar ( '>' ); /* 終了前に確認 */ putchar ( getchar() ); /* ハノイの終了 */ s_hanoi_stop(); return 0; }
$ ./20180608-01-QQQQ.exe $