- 1234-a01.c (1234-a01.c (SJIS))
1234-a01.c
#include <stdio.h>
void print_dictum(void) {
printf ( "女は三界に家なし\n" );
}
int main(void) {
print_dictum();
return 0;
}
- 20200626-01.c (20200626-01.c (SJIS))
20200626-01.c
/*
* 20200626-01-QQQQ.c
* 英小文字を英大文字に、英大文字を英小文字に入れ替える関数
*/
#include <stdio.h>
/*
* char change_up_lower ( char ch )
* 引数で指定された文字が大英文字なら英小文字に、英小文字なら英大文字にする
*/
char change_up_lower ( char ch ) {
/* 英大文字の処理 */
/* 'A' <= ch <= 'Z' -> ch に英大文字を表す文字コード */
/* 'A' <= ch と ch <= 'Z' の両方の条件チェックする */
if ( 'A' <= ch ) { /* もし、 ch が 'A' 以上で .. */
if ( ch <= 'Z' ) { /* しかも、 'Z' 以下 なら .. */
/* 引数は英大文字だったので、英小文字に変換し、値を返す */
return ch - 'A' + 'a';
/*
ch = 'A' => return 'a';
ch = 'B' => return 'b';
..
ch = 'Z' => return 'z';
*/
/* 英大文字 : 返り値として英小文字が返る
return 命令を実行するので、ここで関数が終了する
*/
} /* else は省略 */
}
/* 英小文字の処理 */
if ( 'a' <= ch ) { /* もし、 ch が 'a' 以上で .. */
if ( ch <= 'z' ) { /* しかも、 'z' 以下 なら .. */
/* 引数は英小文字だったので、英大文字に変換し、値を返す */
return ch - 'a' + 'A';
}
}
/* 何れでもない場合 */
return ch; /* 引数の値をそのまま、関数の値として返す */
}
/*
* main
*/
int main ( void ) {
/* 英大文字 ( 'Q' ) の場合 */
printf ( "英大文字 ( 'Q' ) の場合 「" );
putchar ( change_up_lower ( 'Q' ) );
printf ( "」となります。\n" );
/* 英小文字 ( 'h' ) の場合 */
printf ( "英小文字 ( 'h' ) の場合 「" );
/*
** この部分を完成させなさい
*/
printf ( "」となります。\n" );
/* 何方でもない ( '4' ) の場合 */
printf ( "何方でもない ( '4' ) 場合 「" );
putchar ( change_up_lower ( '4' ) );
printf ( "」となります。\n" );
return 0;
}
- 20200626-02.c (20200626-02.c (SJIS))
20200626-02.c
/*
* 20200626-02-QQQQ.c
* 指定した文字列の中の英小文字を英大文字に、英大文字を英小文字に入れ替えて出力する関数
*/
#include <stdio.h>
#define EOS '\0' /* マクロ(EOS) を、NULL 文字 '\0' で定義 */
/* 以下の結果は、20200626-01-QQQQ.c の内容を、そのまま利用する */
/*
* char change_up_lower ( char ch )
* 引数で指定された文字が大英文字なら英小文字に、英小文字なら英大文字にする
*/
char change_up_lower ( char ch ) {
/* 英大文字の処理 */
if ( 'A' <= ch ) { /* もし、 ch が 'A' 以上で .. */
if ( ch <= 'Z' ) { /* しかも、 'Z' 以下 なら .. */
/* 引数は英大文字だったので、英小文字に変換し、値を返す */
return ch - 'A' + 'a';
}
}
/* 英小文字の処理 */
if ( 'a' <= ch ) { /* もし、 ch が 'a' 以上で .. */
if ( ch <= 'z' ) { /* しかも、 'z' 以下 なら .. */
/* 引数は英小文字だったので、英大文字に変換し、値を返す */
return ch - 'a' + 'A';
}
}
/* 何れでもない場合 */
return ch; /* 引数の値をそのまま、関数の値として返す */
}
/*
* void print_change_up_lower_string ( char *string )
* 引数で指定した文字列の中の英小文字を英大文字に、
* 英大文字を英小文字に入れ替えて出力する関数
*/
void print_change_up_lower_string ( char *string ) {
if ( *string == EOS ) { /* 空文字列 ("") だった.. */
/* 何もしない */
} else {
/* 取り敢えず、先頭の文字だけ変換を行って、出力 */
putchar ( change_up_lower ( *string ) );
/* 残りの文字列は、再帰で処理 */
print_change_up_lower_string ( string + 1 );
}
}
/*
* main
*/
int main ( void ) {
printf ( "Aa0BB11cc@+Xy\n" );
print_change_up_lower_string ( "Aa0BB11cc@+Xy\n" );
return 0;
}
- 20200626-03.c (20200626-03.c (SJIS))
20200626-03.c
/*
* 20200626-03-QQQQ.c
* 10 未満の長さの文字列の長さを表す一文字の数字を返す関数
*/
#include <stdio.h>
#define EOS '\0' /* マクロ(EOS) を、NULL 文字 '\0' で定義 */
/*
* char length_of_string ( char *string )
* 引数の文字列の長さを表す、一桁の数字を返す関数
* 文字列の長さは一桁の場合しか、「適切に動作」しない
*
* length_of_string ( "abc" ) => '3'
* length_of_string ( "" ) => '0'
* length_of_string ( "1234567890" ) => NG
*
* length_of_string ( "abc" ) => '3'
* length_of_string ( "abc" + 1 ) + 1
* length_of_string ( "bc" ) + 1
* '2' + 1
* '3'
* length_of_string ( "bc" ) => '2'
* length_of_string ( "abc" + 1 ) => '2' = '3' - 1
*/
char length_of_string ( char *string ) {
if ( *string == EOS ) { /* 空文字列なら、長さは 0 */
return '0'; /* 長さ「0」を表す『文字(数字)』「'0'」を返す */
} else {
/* 一文字分短い『文字列』の長さに対する数字を再帰で求め、それに 1 を加える */
return length_of_string ( string + 1 ) + 1;
}
}
/*
* main
*/
int main ( void ) {
printf ( "文字列「\"abc\"」の長さは " );
putchar ( length_of_string ( "abc" ) );
printf ( " です。\n" );
printf ( "文字列「\"123456\"」の長さは " );
putchar ( length_of_string ( "123456" ) );
printf ( " です。\n" );
/* 長さが 10 を越える場合は、不適切な結果になる */
printf ( "文字列「\"1234567890123\"」の長さは " );
putchar ( length_of_string ( "1234567890123" ) );
printf ( " です。\n" );
return 0;
}
- 20200717-02.c (20200717-02.c (SJIS))
20200717-02.c
/*
* CDATE FILENAME
*
* 与えられた自然数の素因数を出力する
*
* 12 は..
*
* [コンパイル]
* cc -I ~/include -c FILENAME
* [リンク]
* cc -o BASENAME.exe BASENAME.o
* [実行]
* ./BASENAME.exe
*
* 12 : 12=2^2*3 => 2 2 3
*/
#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 未満の素因数を含まれていない自然数
* 返り値 : なし
*
* f(12,2) => 2 2
* 2 f(6,2) = 2 f(12/2,2)
* [手でやる]
* 12 => 2 と (12/2)
*
* 12 ( 2
* -----
* 6 ( 2
* -----
* 3 ( 3
* -----
* 1
*/
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 の要素があるかもしれないので、そこから試す [再帰] */
print_prime_factor_sequence ( n / p, p );
} else { /* n が p を素因数として含まない */
/* 本来は p の次の素数を試すべきだが.. */
/* その代りに p + 1 を試す (のは無駄だが、正く動く) [再帰] */
/*
print_prime_factor_sequence ( n , p の次素数 );
*/
print_prime_factor_sequence ( n, p + 1 );
/*
p が素数だとしても
p + 1 は素数であるという保証がない
それでよいのか ??
n は p より小さい素因数をもっていない
素数 => OK
p+1 {
合成数 => 素因数分解
p + 1 = q1 * q2 * .. *
qi < p
p+1 は n の約数になりえない
=>
なにもおきずに、
次の次の p + 1 + 1 を試す
=> これ繰り返して、
p が次の素数になるまで増え続ける
*/
}
}
/*
* 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 ( "の素因数分解は" );
print_prime_factor_sequence ( n , 2 );
s_print_string ( " となります。\n" );
}
}
/*
* main
*/
int main( void )
{
print_prime_factor_of ( 12 );
return 0;
}
- 20200717-03.c (20200717-03.c (SJIS))
20200717-03.c
/*
* 20200717-03-QQQQ.c
* フィボナッチ数列の第 n 項を返す関数
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* int fibonacci ( int n )
* 引数で指定された n 番目 ( n = 0 〜 ) のフィボナッチ数を値として返す関数
* ただし、n 番目のフィボナッチ数 fib(n) は次のように再帰的に定義
* 0 (n = 0 の時)
* fib(n) = { 1 (n = 1 の時)
* fib(n-1) + fib(n-2) (n > 1 の時)
*
* 注意 : 引数に負の数を指定された場合の値は「未定義」
*/
int fibonacci ( int n ) {
if ( n < 2 ) {
/* 本来は n = 0, n = 1 の時の処理 */
/* fib(0) = 0, fib(1) = 1 なので 0 <= n <= 1 の時 fib(n) = n */
return n;
/* n < 0 (負の数) の時は、『未定義』なので、勝手に n を返している */
/* 本来は『未定義』の場合を含めるべきでない */
} else {
/* 再帰を利用して計算 */
return fibonacci(n-1)+fibonacci(n-2);
/* 再帰の対象が、複数よい */
/* 問題が(再帰によって)解きやすい .. */
/* 問題を解く
-> 複数小問題に分割
n => (n - 1) + 1
n => n/2 + n/2
*/
}
}
/*
*
*/
void print_fibonacci ( int n ) {
s_print_int ( n );
s_print_string ( " 番目のフィボナッチ数は " );
s_print_int ( fibonacci ( n ) );
s_print_string ( " です。\n" );
}
/*
* main
*/
int main ( void ) {
s_print_string ( "整数値 n を入力してください : " );
print_fibonacci ( s_input_int() );
s_print_string ( "整数値 n を入力してください : " );
print_fibonacci ( s_input_int() );
return 0;
}
- p-001.c (p-001.c (SJIS))
p-001.c
#include <stdio.h>
int main(void) {
printf ( "女は三界に家なし\n" );
return 0;
}
- p-002.c (p-002.c (SJIS))
p-002.c
#include <stdio.h>
void print_dictum(void) {
printf ( "女は三界に家なし\n" );
}
int main(void) {
print_dictum();
return 0;
}
- p-003.c (p-003.c (SJIS))
p-003.c
#include <stdio.h>
/*
* 引数で指定された整数値回だけメッセージ(Hello, World)を出力する
*/
void n_times( int n ) {
if ( n <= 0 /* n == 0 */ ) {
/* 何もする事はない */
} else {
printf ( "Hello, World\n" ); /* 繰り返される */
n_times ( n - 1 );
}
}
int main(void) {
printf ( "n=3 の場合\n" );
n_times ( 3 );
printf ( "n=5 の場合\n" );
n_times ( 5 );
return 0;
}
- p-004.c (p-004.c (SJIS))
p-004.c
#include <stdio.h>
#include "s_print.h"
#include "s_input.h"
/*
* 階乗(n!)の計算を行う
* factrial
* 引数は整数値が一つ、返り値が整数型
*
* 1 (n=0)
* n 階乗 : n! = {
* n * ((n-1)!) (n>0)
* 帰納的に定義されている関数を再帰的関数として実装
*/
int factrial( int n ) {
if ( n <= 0 /* n == 0 */ ) { /* n が 0 の時 */
/* 答えは 1 */
return 1;
} else { /* n が 0 より大きい時 */
return n * factrial ( n - 1 );
}
}
int main(void) {
printf ( "整数値を一つ入力してください : " );
s_print_int ( factrial ( s_input_int() ) );
s_print_newline();
return 0;
}
- p-005.c (p-005.c (SJIS))
p-005.c
#include <stdio.h>
/*
0 (n=0 の時)
sum(n) = {
sum(n-1)+n (n>0 の時)
*/
#include "s_print.h"
#include "s_input.h"
int sum(int n) {
if ( n <= 0 /* n == 0 */ ) {
return 0;
} else {
return sum(n-1) + n;
}
}
int main(void) {
s_print_string ( "整数値を入力してください : " );
s_print_int ( sum( s_input_int() ) );
s_print_newline();
return 0;
}
- p-006.c (p-006.c (SJIS))
p-006.c
#include <stdio.h>
/*
0 (n=0 の時)
sum(n) = {
sum(n-1)+n (n>0 の時)
*/
#include "s_print.h"
#include "s_input.h"
int sum_helper( int s, int i, int n ) {
if ( i > n ) {
return s;
} else {
return sum_helper ( s + i, i + 1, n );
/*
sum(n) = 1 + 2 + .. + n
= sum_helper ( 0, 1, n );
=> sum_helper ( 0 + 1, 1 + 1, n );
=> sum_helper ( 1, 2, n );
=> sum_helper ( 3, 3, n );
...
=> sum_helper ( 1+2..+n, n+1, n );
n+1 > n
=> 1+2+..+n
*/
}
}
int sum(int n) {
return sum_helper ( 0, 1, n ); /* 引数に 0 を追加しただけ */
}
int main(void) {
s_print_string ( "整数値を入力してください : " );
s_print_int ( sum( s_input_int() ) );
s_print_newline();
return 0;
}
- memo.txt (memo.txt (SJIS))
memo.txt
前回(2020/07/17)の内容
条件分岐 ( if 構文 / switch 構文 )
再帰 again
if 構文
if ( 条件 ) {
条件が成立した時の命令
} else {
条件が不成立の時の命令
}
基本形 : これだけ知っていれば、なんでもできる
=> よりよい表現 / 他の人のプログラムを読む
=> 基本以外の表現も知っていた方がよい
else 節の省略
「条件が不成立の時の命令」が空の時は、
else 以後(else 節)は、省略可能
if ( 条件 ) {
条件が成立した時の命令
}
else if
else 節の中身が、一つの if 構文の時、
else の {} を省略しよう
<<基本>>
if ( 条件1 ) {
..
} else {
if ( 条件2 ) {
..
} else {
..
}
}
=>
if ( 条件1 ) {
..
} else
if ( 条件2 ) {
..
} else {
..
}
=>
if ( 条件1 ) {
..
} else if ( 条件2 ) {
..
} else {
..
}
# else 節 ( then 節 も ) 命令が一個なら {} は省略可能
# 命令が一つなら
# if ( 条件 )
# 命令 <= 命令が一つの文
# else
# 命令 <= 命令が一つの文
# とできるが、これは、推奨しない
# {}がなくなると、if 構文の範囲がわかりにくなる
# 後になって、命令を増やしたり、減らしたりする事があったら
# {} があれば、命令を増やしたりへらしたりできる
# {} をつけないと、{} が追加が必要
switch 構文
条件分岐を行う構文
if 構文が 2 択 / 任意の条件
switch 構文が n 択 / ある式の値が整数値と一致するかどうか
switch ( 整数式 ) {
case 定数1:
整数式の値が定数1と一致した場合の命令
break;
case 定数2:
整数式の値が定数2と一致した場合の命令
break;
..
case 定数n:
整数式の値が定数nと一致した場合の命令
break;
default:
式の値が定数1?定数n のいずれにも一致しなかった場合の命令
break;
}
<=>
if ( 整数式 == 定数1 ) {
整数式の値が定数1と一致した場合の命令
} else if ( 整数式 == 定数2 ) {
整数式の値が定数2と一致した場合の命令
...
} else if ( 整数式 == 定数n ) {
整数式の値が定数nと一致した場合の命令
} else {
式の値が定数1?定数n のいずれにも一致しなかった場合の命令
}
==
再帰の再び
「関数の再帰的定義」
関数を定義する時に、その本体で、自分自身を呼び出す
# 「定義」
# 新しい概念(言葉や記号であらわす)を、
# 既存の(すでに定義済みの)概念(言葉や記号)で表現する事
# 例:
# 素数
# 自分自身と1の二つだけを約数とする自然数
# 例 : 3 .. 約数 1, 3 / 11 : 11 1
# 反例 : 1 .. 1, 12 = 1, 12, 3, 4
# 素数の定義の時に、約数、自然数などの定義済言葉を使う
再帰的定義
1 (n=0)
n 階乗 : n! = {
n * ((n-1)!) (n>0)
# 再帰的が循環論法になっているようみえるが、大丈夫
# 3! = 3 * 2! = 3 * 2 * 1! = 3 * 2 * 1 * 0! = 3 * 2 * 1 = 6
!!! 「数学的帰納法」を基礎としている
関数を再帰的に定義する
=> 命令を(不特定多数)繰り返す事が可能
組み合わせ基本構文 : 順接、条件分岐、繰り返し
=> 万能
C 言語 : 並べる、if 構文・switch構文、関数の再帰的定義
階乗の関数定義
全体の計算をするために、一部の計算を行い、その結果を用いる
=> 再帰(帰納法)
# n! : 全体 <=> (n-1)! : 一部
# 一部の計算に、再帰が利用できる(と便利な事が多い)
一部の計算結果が、関数の値として得られる
総和:
数列 {n} = 1, 2, 3, .., n の和
Σi = 1 + 2 + 3 + .. + n
sum(n) = 1 + .. + (n-1) + n
= (1 + .. + (n-1)) + n
= sum(n-1) + n
=> 再帰呼び出しの部分
sum(0) = 0
=>
0 (n=0 の時)
sum(n) = {
sum(n-1)+n (n>0 の時)
sum(n) = 0 + 1 + .. + (n-1) + n
= 0 + (1 + .. + (n-1)) + n
= sum(n-1) + n
p-005.c 関数の値が、計算結果の蓄積を行っている
p-006.c 引数の値が、計算結果の蓄積を行っている
計算が終了した時点で、(蓄積された計算結果である)引数の値を返す事により、
関数値が(求める)計算結果になるようにしている
本日(2020/07/24) 18:00 ? 19:00
に「質問の時間(会議 ID : hrh-kuav-nhm)」
模擬試験/試験と同じ会議 ID