/*
* 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 $