/*
 * 20200612-01-QQQQ.c
 *	与えられた文字列の文字を二度ずつ出力する関数を作成する
 */
#include <stdio.h>
#include <string.h>
/*
 * double_print
 *	与えられた文字列(message)の文字を二度ずつ出力する
 */
void double_print ( char *message ) {
  if ( !strcmp ( message, "" ) ) {	/* 空文字列だった */
	/* なにもする必要はない */
  } else {
  	putchar ( *message );		/* 取り敢えず、一つ分は出す */
  	putchar ( *message );		/* 次に、二つ分を出す */
	double_print ( message + 1 );	/* 再帰呼出しをする */
  }
}
/*
 * main
 */
int main ( void ) {
	double_print ( "abc" );
	printf ( "\n" );
	double_print ( "1234567" );
	printf ( "\n" );
	return 0;
}
/*
 * 20200612-02-QQQQ.c
 *	与えられた文字列の文字を逆順に出力する関数を作る
 */
#include <stdio.h>
#include <string.h>
/*
 * reverse_print
 *	与えられた文字列(message)の文字を逆順に出力する
 */
void reverse_print ( char *message ) {
  if ( !strcmp ( message, "" ) ) {	/* 空文字列だった */
	/* なにもする必要はない */
  } else {
	/* ここで再帰呼出しを行うのだが... */
  	reverse_print ( message + 1 );
  	putchar ( *message );
  }
}
/*
 * main
 */
int main ( void ) {
	reverse_print ( "abc" );
	printf ( "\n" );
	reverse_print ( "1234567" );
	printf ( "\n" );
	return 0;
}
/*
	"abc" => "abc"
		"abc"
			'a'   +   "bc"
			putchar   再帰
				=> myprint の実装
	g( "abc" ) => "abc"
		'a'              + "bc"
		putchar ( 'a' )  + g ( "bc" );
		putchar ( *"abc" )  + g ( "abc" + 1 );
	"abc" => "cba"
		"cba"
			"cb" + 'a'
			再帰	putchar
	f( "abc" ) => "cba"
		"cb" + 'a'
		f ( "bc" ) + putchar ( 'a' )
		f ( "abc" + 1 ) + putchar ( *"abc" )
*/
#include <stdio.h>
int main(void) {
	printf ( "Hello, World\n" );
	return 0;
}
#include <stdio.h>
int main(void) {
	putchar ( 'a' );	/* 画面に「文字」「a」を表示する */
	return 0;
}
#include <stdio.h>
int main(void) {
	printf ( "文字を出力する場合は、putchar 関数を使う\n" );
	printf ( "ここに :「" );
	putchar ( 'a' );	/* 画面に「文字」「a」を表示する */
	printf ( "」を表示する\n" );
	return 0;
}
#include <stdio.h>
int main(void) {
	putchar ( 'a' );	/* 画面に「文字」「a」を表示する */
	putchar ( '\n' );	/* 画面に「文字」「改行」を表示する */
		/* 結果的に、画面に「a」と「改行」が表示されるので */
		/* printf ( "a\n" ); と同じ結果になる */
	return 0;
}
#include <stdio.h>
int main(void) {
	printf ( "キーボードから、一文字入力し、さらに [Enter]キーを押してください 「" );
	putchar ( getchar() );
		/* キーボードから一文字入力し、その文字をそのまま出力する */
	/* getchar() は、[Enter] キー(改行キー)を押すまで、待っている */
	printf ( "」\n" );
	return 0;
}
#include <stdio.h>
int main(void) {
	printf ( "キーボードから、文字列を入力し、さらに [Enter]キーを押してください \n" );
	putchar ( getchar() );
	putchar ( getchar() );
	putchar ( getchar() );
	printf ( "\n" );
	return 0;
}
#include <stdio.h>
int main(void) {
	printf ( "キーボードから、文字を入力し、さらに [Enter]キーを押してください \n" );
	putchar ( getchar() + 1 );
		/* 入力された『文字』の次の『文字』が表示される */
	printf ( "\n" );
	return 0;
}
#include <stdio.h>
int main(void) {
	printf ( "キーボードから、文字を入力し、さらに [Enter]キーを押してください \n" );
	putchar ( getchar() - 1 );
		/* 入力された『文字』の前の『文字』が表示される */
	printf ( "\n" );
	return 0;
}
#include <stdio.h>
int main(void) {
	putchar ( *"abc" );	/* 画面に「文字」「a」を表示する */
						/* 『文字列』「"abc"」に「*」つけてると、
							『文字列』の先頭の『文字』である
							「'a'」が得られる */
	return 0;
}
#include <stdio.h>
int main(void) {
	putchar ( *"abc" );				/* 先頭の文字「a」 */
	putchar ( * ( "abc" + 1 ) );	/* 二番目の文字「b」 */
	putchar ( * ( "abc" + 2 ) );	/* 二番目の文字「c」 */
			/* "abc" + 2 => ( "abc" + 1 ) + 1 */
			/*           => "bc" + 1 */
			/*           => "c" */
	printf ( "\n" );
	
	return 0;
}
#include <stdio.h>
int main(void) {
	putchar ( "abc"[0] );	/* 先頭(0番目)の文字「a」 */
	putchar ( "abc"[1] );	/* 二番目の文字「b」 */
	putchar ( "abc"[2] );	/* 三番目の文字「c」 */
	/* "abc"[2] <-> *( "abc" + 2 ) <-> * ( "c" ) <-> 'c' */
	printf ( "\n" );
	
	return 0;
}
#include <stdio.h>
#include <string.h>
/*
 *	myprintf ( char *string );
 *		引数で指定された『文字列』を表示する
 */
void myprintf ( char *string ) {
	/*
		string が空文字列の時とそうでない時に分ける
	*/
	if ( !strcmp ( string, "" ) ) {
		/* 空文字列の時は何もしない */
	} else {
		putchar ( *string );		/* 先頭の『文字』を出力 */
		myprintf ( string + 1 );	/* 残りの『文字列』を出力 (再帰) */
	}
}
int main(void) {
	myprintf ( "Hello, World\n" );
	return 0;
}
#include <stdio.h>
#include <string.h>
/*
 *	myprintf ( char *string );
 *		引数で指定された『文字列』を表示する
 */
void myprintf ( char *string ) {
	/*
		string が空文字列の時とそうでない時に分ける
	*/
	if ( *string == '\0' ) {	/* 『文字列』の先頭の『文字』が「null 文字('\0')」に等しい */
								/* 		=> 『文字列』が「空文字列("")」である事と同じ */
								/* C 言語で「同じ値」を意味する等式記号は「==」を使う */
								/*	=> 「!strcmp ( string, "" )」と同じ */
		/* 空文字列の時は何もしない */
	} else {
		putchar ( *string );		/* 先頭の『文字』を出力 */
		myprintf ( string + 1 );	/* 残りの『文字列』を出力 (再帰) */
	}
}
int main(void) {
	myprintf ( "Hello, World\n" );
	return 0;
}
前回(2020/06/05)の内容
	複雑な数学パズルを、再帰を用いて解決する
		順接/条件分岐/再帰
			=> 万能性
				原理的に解く事ができるものは、解ける
					解くプログラムを作成する事ができる
	再帰的に問題を解くパズル
		ハノイの塔
			高さ N のハノイの塔の問題を解くには
				高さ N-1 のハノイ塔を移動し
				サイズ N の円盤を移動
				高さ N-1 のハノイ塔を移動
					=> 問題をより簡単な問題に分割
						再帰 => 数学的に「正しく問題を解く」事が証明できる
							プログラムが動いたから OK だけでなく
								=> ある特殊な条件ではうまく行く事が保証される
							作成されたプログラムが、「任意の場合」でもうまくゆく事を
								証明する事ができる
									=> 数学の能力が要求される
		砂漠の旅人
	「数学」と「情報」の関係
		プログラムを作成して問題を解く
			「アルゴリズム」:問題を解くための手順
		数学的な「ものの考え方」
			問題を解く鍵(アルゴリズム)になる
				数学の概念でアルゴリズムにつながる考え方
					計算
					色々モデル(数学概念:線形空間/収束/分類/帰納法/背理法/etc..)
C 言語における『文字』
	cf.
		『文字列』: C 言語の表現上の「文字列」を『文字列』であらわす
			「"」で挟さまれた「文字」の並びで表現
				例 : 「"abc"」は、三つの「文字」「a」,「b」,「c」からなる「文字列」を表す
						=> 『文字列』は、長さをもっており、この例では長さ 3 になる
	『文字』: C 言語の表現上の「文字」
		「'」で挟まれた、一つの「文字」で表現
			例 : 「'a'」は、一つの「文字」「a」を表す
				『文字』は、長さはない ( 常に 1 と考えてもよいが、意味がない )
					注意 : 「"a"」は、長さ 1 の『文字列』で、「'a'」は『文字』なので、異なるもの
						C 言語では、『文字』と『文字列』は、まったく違うもの
	文字の入力と出力
		『文字』の出力
			cf.
				『文字列』の出力
					printf 関数を使う
						例: printf ( "abc\n" );
							=> 画面に「abc」と改行が表示される
								エスケープシーケンス : 「\n」は、
									「改行」一文字を表す
			putchar ( 'a' );
				=> 画面に対して、「文字」「a」を出力する
					# 同じ「出力(画面への表示)」機能
					#	出力対象(『文字』と『文字列』)が異なる
					#		=> 異なる関数(putchar,printf)を利用する必要がある
	文字の表現
		文字は「'」で挟む (cf. 「文字列」は「"」で挟む)
		当分は、半角のみ、日本語の「文字」は扱わない
			半角 : 英数、大文字小文字、簡単な記号
				=> ASCII Code 表の対象
		# 実は、C 言語では、「全角の文字」(日本語の漢字)も扱える
		#	色々な制約 : この講義では扱ない
		#		!! 文字コードによって結果異なる
		#		!!		Windows は SJIS / Ubuntu は UTF-8
		#		!!			=> Windows と Ubuntu で結果が違う
		## 「全角文字を含む文字列」は「表示目的」で利用する
	文字の出力
		putchar( 文字 ); を使う
			「putchar ( 'a' );」 で文字('a')が出力される
		改行文字は '\n' で表す : putchar ( '\n' ) で改行する
			エスケープシーケンスは、「文字」の表現にも利用される
				「'\n'」は、「一文字の改行」を表す『文字』を表している
	文字の「入力」
		「出力」=> 画面になにを表示する機能
		「入力」=> キーボードからキーを押して、そのキーに対応する『文字』を
			プログラム内で扱えるようにする機能
		「getchar()」とすると、キーボードからの入力を待つ
			キーボードからキーを押して、さらに[Enter]キーを押すと
				そのキーに対応する『文字』とさらに'\n' が入力される
[プログラム]
	printf ( "キーボードから、一文字入力し、さらに [Enter]キーを押してください 「" );
              ^^^^^^^^^^^^^^^^^^^^^^^^^^(1)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	putchar ( getchar() );
              ========= キーボーから入力 : 入力内容がエコーバック
    ~
	printf ( "」\n" );
	++++++++++++++++++
[出力]
キーボードから、一文字入力し、さらに [Enter]キーを押してください 「a
^^^^^^^^^^^^^^^^^^^(1)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=
= : 「a」と「改行」が表示 : キーボードからの入力 ('a'+[Enter])
a」
~ : 「a」という文字が表示されている : getchar() で入力された『文字』を出力
 ++ : 閉じかっこと改行が表示
	getchar() によって、「プログラムの実行時」に、
		キーボードから入力された『文字』をプログラム内で利用できる
[プログラム]
	printf ( "キーボードから、文字列を入力し、さらに [Enter]キーを押してください \n" );
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
			それぞれ、一文字入力し、出力をする
	putchar ( getchar() );
			ここで、初めて入力待ちになり、
				キーボードから「"abc\n"」が入力される
					最初の文字「'a'」が getchar でとりだされ、出力
						=> 'a' のみ出力
	putchar ( getchar() );
			getchar() が呼ばれて、「入力」が要求されるが、
				すでに、"abc\n" が入力済で、かつ、そのうちの
					先頭の一文字「'a'」は、一つ前の getchar でとりだされているので、
						ここでは、次の「'b'」が取り出され、それが表示される
							=> 'b' のみ出力
	putchar ( getchar() );
							=> 'c' のみ出力
		!!! ここで、まだ、「改行」が残ったまま、食い残しが残っている
	printf ( "\n" );
							=> 改行
[出力]
キーボードから、文字列を入力し、さらに [Enter]キーを押してください
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
abc
==== : 文字列「"abc\n"」: 改行も含め 4 文字
abc
	「putchar ( getchar() );」とすると、入力した文字が出力される
	文字の計算
		cf.
			『文字列』には +1 する事ができた
				=> 先頭の一文字が失われ、長さが 1 短い文字列になる
					例 : "abc" + 1 => "bc"
		『文字』 + 1
			=> 次の『文字』になる
				'a' + 1 => 'b'
				'A' + 1 => 'B'
				'1' + 1 => '2'		!!! '1' + '1' は '2' にならない
									!!! 1 + 1 も '2' ではない ( 2 )
									!!! 「1」と「'1'」は違う物
									!!! 「数値」と「数字」
									!!!		「数字」 => '0' ? '9'
									!!!		「数値」 => 無限に存在する
				じゃ、
					'z' + 1
					'9' + 1
							は... ?
		『文字』の「次」は
			「ASCII コード表順」の次になるので
				'z' + 1 => '{'
			となる。
	逆に、『文字』に「-1」する事により(ASCII コード表順の) 前の『文字』になる 
==
	C 言語では、『文字』が扱える
		プログラム中で表現ができる : 'a' で、「文字」「a」を表す事ができる
		出力ができる : puthar ( 'a' ) で「a」が画面に表示される
		入力ができる : getchar() でキーボードから「文字」が入力できる
		計算ができる : +1 で次の『文字』、-1 で前の『文字』になる
			!!! 『文字』と『文字列』は別物 ( "a" と 'a' )
『文字』と『文字列』の関係
	『文字列』「"abc"」は、三つの「文字」「a」,「b」,「c」からなる
		=> 長さは 3 になる
			「文字」「a」は、C 言語では、「'a'」なので、この関係がどうなっているか
	『文字列』から、その一部である『文字』を取り出す方法
		# 『文字列』を『文字』に分解する方法
		#		!!! 分解 => 合成もあるが、二周目
	「*」演算子 ( ポインター剥ぎ / 間接参照演算子 )
		『文字列』の先頭に「*」を付けると、「先頭の『文字』」が取り出せる
			例 : *"abc" => 'a'
		=> 先頭以外の文字は ??
			『文字列』「"abc"」の二文字目: 『文字』「'b'」
				!!! 『文字列』の計算
				!!!		"abc" +1 => "bc" 
			=> * ( "abc" + 1 )
	「[]」演算子
		*( X + i ) <-> X[i]
			X : 何か ( 文字列 )
			i : 整数値
		例:
			*"abc" <-> *( "abc" + 0 ) <-> "abc"[0] <-> 'a'
			*( "abc" + 1 ) <-> "abc"[1] <-> 'b'
			*( "abc" + 2 ) <-> "abc"[2] <-> 'c'
	「空文字列」へ「*」をつけるとどうなるか ?
		=> 結果は、「null 文字」「'\0'」になる
		*"" => '\0'
			!!! 空文字列は「""」で、「null 文字」は「'\0'」の事
			!!!		=> 全然違う
		イメージとして、
			"abc" は、{ 'a', 'b', 'c', '\0' }となるもの
			!!! 『文字列』の最後には必ず「null 文字」がいる
			!!!		=> 「null 文字」が『文字列』の終わりを表す
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20200612-01.c
/*
 * 20200612-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;
}
$ ./20200612-01-QQQQ.exe aabbcc 11223344556677 $
Download : 20200612-02.c
/*
 * 20200612-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;
}
$ ./20200612-02-QQQQ.exe cba 7654321 $