Download : sample-001.c
/*
* 2021/06/18 sample-001.c
*/
/*
* 返値を持つ関数
*/
#include <stdio.h>
/*
* to_upper : 引数で与えられた文字が小文字なら大文字にする
*/
char to_upper ( char ch ) {
if ( 'a' <= ch ) { /* もし、ch が 'a' 以上で.. */
if ( ch <= 'z' ) { /* 更に、ch が 'z' 以下なら.. */
return ch - 'a' + 'A'; /* 小文字なので大文字に変換して返す */
/* return 命令が実行されると、そこで関数は終了 */
} /* else {} */ /* else 以下はないので省略 */
} /* else {} */
return ch; /* 小文字でない場合は、そのまま返す */
}
/*
* main 関数
*/
int main ( void ) {
printf ( "一文字入力して、[Enter] キーを押してください : " );
putchar ( to_upper ( getchar() ) );
putchar ( '\n' );
return 0;
}
k
$ ./sample-001.exe < sample-001.in 一文字入力して、[Enter] キーを押してください : k K $
Download : sample-002.c
/*
* 2021/06/18 sample-002.c
*/
/*
* main の返値
*/
#include <stdio.h>
/*
* is_upper : ch が大文字なら 1 そうでなければ、0 を返す
*/
int is_upper ( int ch ) {
if ( 'A' <= ch ) {
if ( ch <= 'Z' ) {
return 1; /* 大文字だった.. */
}
}
return 0; /* 大文字ではなかった.. */
}
/*
* main 関数
*/
int main ( void ) {
printf ( "一文字入力して、[Enter] キーを押してください : " );
if ( is_upper ( getchar() ) ) {
printf ( "大文字なので 0 を返します。\n" );
return 0;
} else {
printf ( "大文字でなかったので 1 を返します。\n" );
return 1;
}
}
Q
$ ./sample-002.exe < sample-002.in 一文字入力して、[Enter] キーを押してください : Q 大文字なので 0 を返します。 $
Download : sample-003.c
/*
* 2021/06/18 sample-003.c
*
* コンパイルの方法:
* cc -c -I ~/c/include sample-003.c
*/
/*
* s_print.h の使い方
*/
#include <stdio.h>
#include "s_print.h" /* s_print_... を利用する場合には必要 */
/*
* main 関数
*/
int main ( void ) {
s_print_char ( 'A' ); /* 文字の出力 : putchar ( 'A' ) と同じ */
s_print_newline(); /* 改行の出力 : putchar ( '\n' ) と同じ */
s_print_string ( "Hello, World\n" );
/* 文字列の出力 : printf と同じ */
s_print_int ( 123 ); /* 整数値の出力 */
s_print_newline();
return 0;
}
$ ./sample-003.exe A Hello, World 123 $
Download : sample-004.c
/*
* 2021/06/18 sample-004.c
*
* コンパイルの方法:
* cc -c -I ~/c/include sample-004.c
*/
/*
* s_input.h の使い方
*/
#include <stdio.h>
#include "s_print.h"
#include "s_input.h" /* s_input_... を利用する場合には必要 */
/*
* main 関数
*/
int main ( void ) {
s_print_string ( "一文字を入力して、[Enter] を押してください : " );
s_print_char ( s_input_char () + 1 );
s_print_newline();
s_print_string ( "整数値を一つ入力して、[Enter] を押してください : " );
s_print_int ( s_input_int () + 1 );
s_print_newline();
return 0;
}
B 123
$ ./sample-004.exe < sample-004.in 一文字を入力して、[Enter] を押してください : B C 整数値を一つ入力して、[Enter] を押してください : 123 124 $
Download : sample-005.c
/*
* 2021/06/18 sample-005.c
*
* コンパイルの方法:
* cc -c -I ~/c/include sample-005.c
*/
/*
* 二つの入力を利用する場合
*/
#include <stdio.h>
#include "s_print.h"
#include "s_input.h"
/*
* addfunc
*/
int addfunc ( int a ) {
s_print_string ( "二つ目の整数値を入力して、[Enter] を押してください : " );
return a + s_input_int();
}
/*
* main 関数
*/
int main ( void ) {
s_print_string ( "一つ目の整数値を入力して、[Enter] を押してください : " );
s_print_int ( addfunc ( s_input_int() ) );
s_print_newline();
return 0;
}
123 456
$ ./sample-005.exe < sample-005.in 一つ目の整数値を入力して、[Enter] を押してください : 123 二つ目の整数値を入力して、[Enter] を押してください : 456 579 $
Download : sample-006.c
/*
* 2021/06/18 sample-006.c
*
* コンパイルの方法:
* cc -c -I ~/c/include sample-006.c
*/
/*
* 二つの入力を利用する場合 (失敗例)
*/
#include <stdio.h>
#include "s_print.h"
#include "s_input.h"
/*
* subfunc
*/
int subfunc ( int a, int b ) {
return a - b;
}
/*
* main 関数
*/
int main ( void ) {
s_print_string ( "二つの整数値を入力して、[Enter] を押してください : " );
s_print_int ( subfunc ( s_input_int(), s_input_int() ) );
s_print_newline();
return 0;
}
123 456
$ ./sample-006.exe < sample-006.in 二つの整数値を入力して、[Enter] を押してください : 123 456 333 $
/*
* 20210611-02-QQQQ.c
* 指定した文字列の中の英小文字を英大文字に、英大文字を英小文字に入れ替えて出力する関数
*/
#include <stdio.h>
#include <string.h>
/* 以下の結果は、20210611-01-QQQQ.c の内容を、そのまま利用する */
/*
* char change_up_lower ( char ch )
* 引数で指定された文字が大英文字なら英小文字に、英小文字なら英大文字にする
*/
char change_up_lower ( char ch ) {
/* 英大文字の処理 */
/* 'A' ? 'Z' */
/* 'A' <= ch <= 'Z' */
/* => 二つの条件 */
/* 'A' <= ch と ch <= 'Z' */
if ( 'A' <= ch ) { /* もし、 ch が 'A' 以上で .. */
if ( ch <= 'Z' ) { /* しかも、 'Z' 以下 なら .. */
/* ここに来るのは、二つ条件が共に成立した場合 */
/* 引数は英大文字だったので、英小文字に変換し、値を返す */
return ch - 'A' + 'a'; /* 大文字から小文字への変換 */
/* 上の return 命令が実行されると、その時点で、
関数実行が終了する */
} else {}
} else {}
/* ここにきた場合は、「大文字じゃなかった」場合.. */
/* ch が大文字なら、return 命令が実行され、ここにはこない */
/* 英小文字の処理 */
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 ( !strcmp ( string, "" ) ) { /* 空文字列 ("") だった.. */
/* 何もしない */
} 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;
}
/*
* 20210611-03-QQQQ.c
* 10 未満の長さの文字列の長さを表す一文字の数字を返す関数
* "abc" -> '3'
* "12345" -> '5'
* 考え方:
* "" -> '0' 単純な例
* "1" -> '1'
* "12345" -> '5'
* "12345" -> '5'
* '4' = '5' - 1
* "2345" = "12345" + 1
* 求めたい関数を f() で表す
* f("12345") = '5'
* = '4' + 1
* = f("2345") + 1
* = f("12345"+1) + 1
* f(S) = f(S+1)+1
*/
#include <stdio.h>
#include <string.h>
/*
* char length_of_string ( char *string )
* 引数の文字列の長さを表す、一桁の数字を返す関数
* 文字列の長さは一桁の場合しか、「適切に動作」しない
*/
char length_of_string ( char *string ) {
if ( !strcmp(string,"") ) { /* 空文字列なら、長さは 0 */
return '0'; /* 長さ「0」を表す『文字(数字)』「'0'」を返す */
} else {
/* 一文字分短い『文字列』の長さを再帰で求め、それに 1 を加える */
return length_of_string ( string + 1 ) + 1;
/* f(S) = f(S+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;
}
/*
* 20210618-01-QQQQ.c
* 文字の種類に応じて、その種類を表す文字を返す関数
* 種別 範囲 返す文字
* 英大文字 A-Z A
* 英子文字 a-z a
* 数字 0-9 0
* その他 ?
*/
#include <stdio.h>
/*
* char_type : 引数で与えられた文字の種類を表す文字を返す関数
*/
char char_type ( char ch ) {
/* 英大文字かどうかをチェック */
/* 'A' <= ch <= 'Z' */
if ( 'A' <= ch ) { /* もし、ch が 'A' 以上で.. */
if ( ch <= 'Z' ) { /* 更に、ch が 'Z' 以下なら.. */
/* ここにくるということは、英大文字 */
return 'A'; /* 'A' を返す */
} /* else {} */ /* else 以下はないので省略 */
} /* else {} */
/* else 節が空の場合は、else ごと省略してよい */
/* 英小文字かどうかをチェック */
if ( 'a' <= ch ) { /* もし、ch が 'a' 以上で.. */
if ( ch <= 'z' ) { /* 更に、ch が 'z' 以下なら.. */
return 'a'; /* 英小文字なので 'A' を返す */
} /* else {} */ /* else 以下はないので省略 */
} /* else {} */
/* 数字かどうかをチェック */
/* '0' <= ch <= '9' */
/* '0' <= ch, ch <= '9' の二つの条件をチェック */
if ( '0' <= ch ) { /* もし、ch が '0' 以上で.. */
if ( ch <= '9' ) {
return '0';
} /* else {} */
} /* else {} */
/* 上記のいずれでもない場合は、'?' を返す */
return '?';
}
/*
* change_char_type : 一行分、キーボードから文字列を読込、そのタイプに変換
*/
void change_char_type ( char ch ) {
if ( ch == '\n' ) { /* 改行ならば、一行分の処理は終り */
/* do nothing */
} else { /* 文字のタイプを表示し、再帰処理 */
putchar ( char_type ( ch ) );
change_char_type ( getchar() );
}
}
/*
* main 関数
*/
int main ( void ) {
printf ( "一行文字列入力して、[Enter] キーを押してください : " );
change_char_type ( getchar() );
putchar ( '\n' );
return 0;
}
#include <stdio.h>
int main(void) {
printf ( "1. Hello, World\n" ); /* 命令: メッセージを画面出力する */
printf ( "2. Hello, World\n" ); /* 命令を並べる : 順接 */
printf ( "3. Hello, World\n" );
return 0;
}
#include <stdio.h>
#include <string.h> /* strcmp を利用する場合 */
/* stdio.h の中に printf の extern 宣言がある */
/* 同様に、string.h の中に strcmp の宣言がある */
int main(void) {
if ( !strcmp ( "abc", "abc" ) ) { /* 二つの文字列は等しい */
printf ( "二つの文字列は等しい\n" ); /* こちらの命令が実行される */
} else {
printf ( "二つの文字列は等しくない\n" );
}
if ( !strcmp ( "abc", "xyz" ) ) { /* 二つの文字列は等しくない */
printf ( "二つの文字列は等しい\n" );
} else {
printf ( "二つの文字列は等しくない\n" ); /* こちらの命令が実行される */
}
return 0;
}
#include <stdio.h>
#include <string.h>
/*
あて名書き
先生の名前の場合は、「先生」それ以外は「様」を付ける
栗野、渡辺 => 先生
その他 => 様
*/
void atena ( char *name ) {
if ( !strcmp ( name, "栗野" ) ) {
printf ( name );
printf ( "先生\n" );
} else {
/* if 構文の「入れ子」を行っている */
/* => if 構文の中で、さらに if 構文を利用している */
if ( !strcmp ( name, "渡辺" ) ) {
printf ( name );
printf ( "先生\n" );
} else {
printf ( name );
printf ( "様\n" );
}
}
}
int main(void) {
atena ( "鈴木" );
atena ( "佐藤" );
atena ( "栗野" );
atena ( "渡辺" );
return 0;
}
#include <stdio.h>
#include <string.h>
/*
あて名書き
先生の名前の場合は、「先生」それ以外は「様」を付ける
栗野、渡辺 => 先生
その他 => 様
新しい版 : 小紫先生の名前もあつかえるようにした
*/
void atena ( char *name ) {
if ( !strcmp ( name, "栗野" ) ) {
printf ( name );
printf ( "先生\n" );
} else {
/* if 構文の「入れ子」を行っている */
/* => if 構文の中で、さらに if 構文を利用している */
if ( !strcmp ( name, "渡辺" ) ) {
printf ( name );
printf ( "先生\n" );
} else {
/* さらに入れ子になっている */
if ( !strcmp ( name, "小紫" ) ) {
printf ( name );
printf ( "先生\n" );
} else {
printf ( name );
printf ( "様\n" );
}
}
}
}
int main(void) {
atena ( "小紫" );
atena ( "鈴木" );
atena ( "佐藤" );
atena ( "栗野" );
atena ( "渡辺" );
return 0;
}
#include <stdio.h>
#include <string.h>
/*
あて名書き
先生の名前の場合は、「先生」それ以外は「様」を付ける
栗野、渡辺 => 先生
その他 => 様
新しい版 : 小紫先生の名前もあつかえるようにした
*/
void atena ( char *name ) {
if ( !strcmp ( name, "栗野" ) ) {
printf ( name );
printf ( "先生\n" );
} else if ( !strcmp ( name, "渡辺" ) ) {
printf ( name );
printf ( "先生\n" );
} else if ( !strcmp ( name, "小紫" ) ) {
printf ( name );
printf ( "先生\n" );
} else {
printf ( name );
printf ( "様\n" );
}
}
int main(void) {
atena ( "小紫" );
atena ( "鈴木" );
atena ( "佐藤" );
atena ( "栗野" );
atena ( "渡辺" );
return 0;
}
#include <stdio.h>
void rec_func(void) { /* 関数 rec_func の定義 */
printf ( "Hello, World\n" );
rec_func(); /* 本体で、自分自身 (rec_func())を呼び出す */
}
int main(void) {
rec_func();
/*
rec_func()
=>
printf ( "Hello, World\n" );
=> 「Hello, World」と表示
rec_func();
=>
printf ( "Hello, World\n" );
=> 「Hello, World」と表示
rec_func();
=>
printf ( "Hello, World\n" );
=> 「Hello, World」と表示
rec_func();
....
延々と「Hello, World」と表示続ける
*/
return 0;
}
#include <stdio.h>
#include <string.h>
void rec_func( char *length ) { /* 関数 rec_func の定義 */
/* length は、1 進法で、繰り返す回数を表す */
/* => length で指定された文字列の文字の個数回だけ繰り返す */
if ( !strcmp( length, "" ) ) { /* 条件成立 : 繰り返しをやめる条件 */
/* 繰り返す回数が 0 の時は、やめてよい */
/* => 引数 length の長さが 0 */
/* 再帰呼び出しをしなければなんでもよい(特に、空でもよい) */
} else {
/* 条件が不成立の時に、再帰呼び出し (繰り返す) */
printf ( "Hello, World\n" ); /* <= 繰り返されるのはこの命令 */
rec_func( length + 1 ); /* 本体で、自分自身 (rec_func())を呼び出す */
/* 引数の値を変更:変更を繰り返す事により、
最終的に、繰り返しが終了するように書き換える */
/* 文字列 に対して 1 を加えると、
文字列の長さが 1 だけ短くなる */
}
}
int main(void) {
rec_func( "***" ); /* 長さ 3 の文字列を指定する */
/*
rec_func( "***" )
=>
"***" -> length
if ( !strcmp( length, "" ) ) {
} else {
printf ( "Hello, World\n" );
rec_func( length + 1 );
}
=>
if ( !strcmp( "***", "" ) ) {
} else {
printf ( "Hello, World\n" );
rec_func( "***" + 1 );
}
=>
printf ( "Hello, World\n" ); 命令を一回繰り返すと同時
rec_func( "**" ); 文字列の長さが 1 減る
=>
-> 「Hello, World」
"**" -> length
if ( !strcmp( length, "" ) ) {
} else {
printf ( "Hello, World\n" );
rec_func( length + 1 );
}
=>
-> 「Hello, World」
if ( !strcmp( "**", "" ) ) {
} else {
printf ( "Hello, World\n" );
rec_func( "**" + 1 );
}
=>
-> 「Hello, World」
printf ( "Hello, World\n" );
rec_func( "*" );
=>
-> 「Hello, World」
-> 「Hello, World」
"*" -> length
if ( !strcmp( length, "" ) ) {
} else {
printf ( "Hello, World\n" );
rec_func( length + 1 );
}
=>
-> 「Hello, World」
-> 「Hello, World」
if ( !strcmp( "*", "" ) ) {
} else {
printf ( "Hello, World\n" );
rec_func( "*" + 1 );
}
=>
-> 「Hello, World」
-> 「Hello, World」
printf ( "Hello, World\n" );
rec_func( "" );
=>
-> 「Hello, World」
-> 「Hello, World」
-> 「Hello, World」
"" -> length
if ( !strcmp( length, "" ) ) {
} else {
printf ( "Hello, World\n" );
rec_func( length + 1 );
}
=>
-> 「Hello, World」
-> 「Hello, World」
-> 「Hello, World」
if ( !strcmp( "", "" ) ) {
} else {
printf ( "Hello, World\n" );
rec_func( "" + 1 );
}
=>
-> 「Hello, World」
-> 「Hello, World」
-> 「Hello, World」
*/
return 0;
}
#include <stdio.h>
#include <string.h>
/*
繰り返しのイデオム
命令 A を、引数で指定した文字列の長さだけ実行するには
次のような再帰呼び出しのパターンを利用すればよい
void rec_A ( char *lengh ) {
if ( !strcmp ( length, "" ) ) {
} else {
命令 A
rec_A ( length + 1 );
}
}
と、関数 rec_A を定義し、実引数に、
命令 A を繰り返したい回数の長さの文字列を指定すればよい
*/
void func ( void ) {
printf ( "Hello, World\n" );
}
void rec_func( char *length ) {
if ( !strcmp( length, "" ) ) {
} else {
func(); /* 繰り返される命令 */
rec_func( length + 1 );
}
}
int main(void) {
rec_func( "***" ); /* 長さ 3 の文字列を指定する */
return 0;
}
#include <stdio.h>
/* 関数定義 */
void printHello (void) {
printf ( "Hello, World\n" );
}
int main(void) {
/* 関数呼び出し */
printHello();
return 0;
}
#include <stdio.h>
/* 引数付き関数の定義 */
/*
関数定義の頭部で、仮引数変数宣言を行う
関数定義の本体で、その仮引数変数を含む命令を書く
=> 命令の一部を、変数に置き換える
*/
void printSomething (char *any) { /* any に文字列が入る場合 */
printf ( "Hello, " );
printf ( any ); /* 後から、別の物 (any) を出したい */
printf ( "\n" );
}
int main(void) {
/* 関数呼び出し */
/* 関数本体に現れる変数に入れる値を実引数として与える */
printSomething( "World" ); /* Hello, World と出力される */
printSomething( "世界" ); /* Hello, 世界と出力される */
return 0;
}
#include <stdio.h>
int main(void) {
printf ( "A" ); /* 文字列「A」を出力する */
putchar ( 'A' ); /* 文字「A」を出力する */
/* 文字列を出力する関数と文字を出力する関数が異なる */
/* => 文字列と文字は型が異なる
処理の仕方が異なる
同じ事をしても、違う結果になったり、
例: 「文字列 + 1」, 「文字 + 1」
同じ +1 なのに、結果が違う
文字列 => 先頭の文字が欠けて、一文字分短くなる
文字 => ASCII コード表の次の文字になる
できる事とできない事がある
例: 「*文字列」 はできる (先頭の文字を取り出す)
「*文字」 はできない
*/
printf ( "\n" ); /* 改行 */
return 0;
}
#include <stdio.h>
void sp( char *x ) {
printf ( x ); /* 変数 x に入る値は文字列である事が想定される */
}
void cp( char x ) {
putchar ( x ); /* 変数 x に入る値は、文字である事が想定される */
}
/* 値を直接指定する場合は、型を間違える事が少ないが、
変数を経由すると、その変数に入っている値の型が見えないので、
型を間違える(不適切な型の値を指定してしまう)危険がある
型宣言(変数に入る値の型を指定する)事により、
その誤りをコンパイラがチェックしてくれる
*/
int main(void) {
sp( "A" ); /* 実引数には、仮引数変数で宣言されている型の値を指定する */
cp( 'A' );
printf ( "\n" ); /* 改行 */
return 0;
}
#include <stdio.h>
void sp( char *x ) {
printf ( x );
}
void cp( char x ) {
putchar ( x );
}
int main(void) {
sp( 'A' ); /* 実引数の型と仮引数変数の型が異なる */
cp( "A" ); /* 間違った指定をした場合にエラーになる */
printf ( "\n" ); /* 改行 */
return 0;
}
#include <stdio.h>
int main(void) {
putchar(getchar()+1); /* getchar() で、キーボードから一文字読み込む */
/* getchar() の返した値を putchar() で出力する */
return 0;
}
#include <stdio.h>
/* +1 の部分を関数にしたい.. */
/*
文字から(ASCII コード表の次の)文字にしたい
値を持つ
*/
char inc(char ch) { /* 文字から文字なので返り値の型と引数型をそれぞれ char */
/* 値として返したいものは、与えられた文字の次の文字 ( +1 した文字 ) */
return ch + 1; /* 「ch+1」という式の値を計算し、その計算結果を関数の返り値としてしてし
さらに、関数を即座に終了する */
}
int main(void) {
putchar(inc(getchar())); /* getchar() で、キーボードから一文字読み込む */
/* getchar() の返した値を putchar() で出力する */
return 0;
}
#include <stdio.h>
#include "s_print.h" /* s_print.h は「"」で挟む */
#include "s_input.h"
int main(void) {
/* s_print_string */
s_print_string ( "Hello, World\n" );
s_print_int ( 123 ); /* 整数値を出力する */
s_print_newline(); /* 改行を出力する */
s_print_int ( 123 + 456 ); /* 整数の計算式は計算されて出力される */
s_print_newline(); /* 改行を出力する */
s_print_string ( "整数値を入力してください。倍にして表示します\n" );
s_print_int ( s_input_int() * 2 );
s_print_newline();
/*
printf ( "Hello, World\n" );
*/
return 0;
}
前回(2021/06/11)の内容
先々週から、二周目(最初から、詳しくもう一度)
Hello, World
色々なおまじない(例:#include)の解説
制御構造
先週(二周目)
「関数」という考え方
「プログラムの一部(命令)」に「名前」を付ける事
!!! 命令列は、「順接」を複数の命令に適用したもの
!!! なので、結局、一つの「命令」になっている
!!! => 関数呼び出しは、一つの「命令」
関数の定義方法
命令列に名前を付ける事
書き方
0. 名前をきめて、それを書く
1. 名前の前に void、後ろに (void)
2. その続きに {, }
3. { と } の間に名前を付けたい命令(列)を書く
関数の呼出し方法
名前を付けた、命令を、その名前(関数名)を利用して、
呼び出す表現
書き方
0. 関数名書き
1. 名前の後ろに (); を付ける
引数付き関数
名前をつける命令の中に、変数を含める事により、
後から、変数の値を指定する事により、
同じ命令なのに、異なる振る舞いさせる事ができる
記述方法
定義
仮引数変数の宣言を行う
呼び出し
実引数を指定する
仮引数変数の宣言の時
変数の名前と同時、(その前に..) その変数に入る値の型を指定する必要がある
具体例:
文字列の時 char *
文字 char
文字を引数に持つ関数と型宣言
文字を引数に持つ関数 : char * から char
仮引数変数の「型宣言」
(実引数として与えられる)値の型がわからないと、
その値を利用する(演算する)方法がわからない
=> 型を指定する事によって、
値の処理の方法を指示する必要がある
「文字」というデータ型
「文字」の比較 / 「文字」の計算
出力には putchar を使う / getchar で入力ができる
C 言語の関数にも「値」を持つ(返す)ものがある
=> 最初の例と紹介したのが getchar()
入力-処理-出力 ( Input - Process - Output )
例: p-014.c
input -> getchar()
process -> +1 <= 目的
output -> putchar()
getchar()
キーボードから文字を入力して、それを値とする関数
値を返す関数 (1)
今までの関数と違い
1. 関数前にある void -> 関数が返す値の型
2. 本体に 「return 式」命令を書く事により、
関数の値を return の後ろの「式」で指定できる
「return 式」命令には二つ機能がある
a) この命令を実行すると、即座に関数を終了する
=> 制御構造 ( 命令の実行順序に影響を与える .. )
b) 関数の終了に際して、return の後ろにある式の値を関数の返り値にする
2021/06/18
順接
命令を並べると、その命令が、並べた順に実行される
cf.
プログラム : 命令を並べたもの
命令(C 言語における命令の典型的な形:関数呼び出し)
関数呼び出し ( printf 関数を呼び出す )
=> 関数に機能が働いて、「何か」がおきる
具体例 :
printf ( 文字列 ) => 文字列が画面に表示される
putchar ( 文字 ) => 文字が画面に表示される
個々の関数が何をするかは、すこしずつ学ぶ必要がある
「命令と命令を組み合わせて、新しい命令を作る」
『命令』を対象する記述(一種のメタ命令)
=> 制御構造
条件分岐
if 構文 ( <= 「if 『文』」とは呼ばない )
!!! if 構文 : 命令とは次元が異なる
if ( 条件 ) {
条件が成立した時の命令A /* then 節 */
} else {
条件が不成立の時の命令B /* else 節 */
}
if 構文によって、命令A と命令 B から、
新しい命令が作られる
「文」<= 命令に対して使う言葉
条件
文字列の比較の場合
!strcmp ( A, B ) 文字列 A と B が等しい
文字の比較の場合
A == B 等しい文字
A != B 等しく文字
A < B 文字 A が ASCII コード表順で B より小さい
A > B 〃 大きい
A <= B 文字 A が ASCII コード表順で B より以下
A >= B 〃 以上
!! 「=>」という比較演算子はない
if 構文(条件分岐)を利用すると、
条件によって、二つの命令のどちらか一方を実行するような
(新しい)命令が作られる
=> if 構文を「入れ子」にする事により、
二つより多くの命令のいずれか一つを実行するようにできる
else if 構文
else 節全体が一つの if 構文の時、
else 節を囲む { と } を省略する表現
繰り返し
再帰呼び出しを利用する事により、
与えられた命令を、繰り返すよう新しい命令が作れる
再帰呼び出しの書き方
=> 関数を定義する時に、関数の本体に、自分自身を呼び出す
!! 注意
!! 無条件に再帰呼び出しをすると、無限ループになる
!! 「与えられた命令を繰り返す(新しい)命令」を作る
!! <= 上手に、適当なところで、繰り返しをやめるようにする
!! if 構文を利用して、
!! 再帰呼び出しをする命令とそうでない命令を組み合わせる
!! if 構文の条件のところに変数がないとこまる
!! その変数は、関数の引数に基づくものである必要があり
!! その引数は、再帰呼び出しの時に変更されないといけない
!! その変更の結果、いつかは、再帰呼び出しをしない命令が if 構文により実行される必要がある
三つの制御構造 ( 順接、条件分岐、繰り返し ) があれば、
実は、任意の命令が、この制御構造の繰り返し適用で、実現可能な事が(数学的に..)わかっている
==
s_print.h
s_input.h
の使い方
1. プログラムの先頭 ( stdio.h の下位.. )
#include "s_print.h"
#include "s_input.h"
書く
2. コンパイルする時に
「-I ~/c/include」を -c の前に挿入する
cc -I ~/c/include -c p-016.c
^^^^^^^^^^^^^^^ 追加部分
3. 次の関数が使える
s_print.h
s_print_string 文字列の出力 ( printf と同じ )
s_print_char 文字の出力 ( putchar と同じ )
s_print_int 整数値の出力
s_input.h
s_input_string 文字列の入力
s_input_char 文字の入力 ( getchar と同じ )
s_input_int 整数値の入力
s_input/s_print
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20210618-01.c
/*
* 20210618-01-QQQQ.c
* 文字の種類に応じて、その種類を表す文字を返す関数
* 種別 範囲 返す文字
* 英大文字 A-Z A
* 英子文字 a-z a
* 数字 0-9 0
* その他 ?
*/
#include <stdio.h>
/*
* char_type : 引数で与えられた文字の種類を表す文字を返す関数
*/
char char_type ( char ch ) {
/* 英大文字かどうかをチェック */
if ( 'A' <= ch ) { /* もし、ch が 'A' 以上で.. */
if ( ch <= 'Z' ) { /* 更に、ch が 'Z' 以下なら.. */
/*
** この部分を完成させなさい
*/
} /* else {} */ /* else 以下はないので省略 */
} /* else {} */
/* 英小文字かどうかをチェック */
if ( 'a' <= ch ) { /* もし、ch が 'a' 以上で.. */
if ( ch <= 'z' ) { /* 更に、ch が 'z' 以下なら.. */
return 'a'; /* 英小文字なので 'A' を返す */
} /* else {} */ /* else 以下はないので省略 */
} /* else {} */
/* 数字かどうかをチェック */
if ( '0' <= ch ) { /* もし、ch が '0' 以上で.. */
/*
** この部分を完成させなさい
*/
} /* else {} */
/* 上記のいずれでもない場合は、'?' を返す */
/*
** この部分を完成させなさい
*/
}
/*
* change_char_type : 一行分、キーボードから文字列を読込、そのタイプに変換
*/
void change_char_type ( char ch ) {
if ( ch == '\n' ) { /* 改行ならば、一行分の処理は終り */
/* do nothing */
} else { /* 文字のタイプを表示し、再帰処理 */
putchar ( char_type ( ch ) );
change_char_type ( getchar() );
}
}
/*
* main 関数
*/
int main ( void ) {
printf ( "一行文字列入力して、[Enter] キーを押してください : " );
change_char_type ( getchar() );
putchar ( '\n' );
return 0;
}
abcABC123()~
$ ./20210618-01-QQQQ.exe 一行文字列入力して、[Enter] キーを押してください : aaaAAA000*** $
Download : 20210618-02.c
/*
* 20210618-02-QQQQ.c
* 二つの整数値を入力して、その余りを出力する
*/
#include <stdio.h>
#include "s_print.h"
#include "s_input.h"
/*
* remainder
*/
int remainder ( int a ) {
s_print_string ( "割る整数を入力して、[Enter] を押してください : " );
/*
** この部分を完成させなさい
*/
}
/*
* main
*/
int main ( void ) {
s_print_string ( "割られる整数を入力して、[Enter] を押してください : " );
s_print_int ( remainder ( s_input_int() ) );
s_print_newline();
return 0;
}
100 13
$ ./20210618-02-QQQQ.exe 割られる整数を入力して、[Enter] を押してください : 100 割る整数を入力して、[Enter] を押してください : 13 9 $