Download : sample-001.c
/*
* CDATE sample-001.c
*/
/*
* 最初は取り敢えず「Hello, World」
*/
#include <stdio.h>
int main ( void ) {
printf ( "Hello, World\n" ); /* "Hello, World" を出力 */
return 0;
}
$ ./sample-001.exe Hello, World $
Download : sample-002.c
/*
* 2019/07/12 sample-002.c
*/
/*
* 順接 : 「Hello, World」を二度出す
*/
#include <stdio.h>
int main ( void ) {
printf ( "Hello, World\n" ); /* "Hello, World" を出力 */
printf ( "Hello, World\n" ); /* 命令を並べれば、並べた通りに実行 */
return 0;
}
$ ./sample-002.exe Hello, World Hello, World $
Download : sample-003.c
/*
* 2019/07/12 sample-003.c
*/
/*
* 異る命令の実行
*/
#include <stdio.h>
int main ( void ) {
printf ( "1 : Hello, World\n" ); /* 一度目の "Hello, World" を出力 */
printf ( "2 : Hello, World\n" ); /* ニ度目、「並べた順」に実行される */
return 0;
}
$ ./sample-003.exe 1 : Hello, World 2 : Hello, World $
Download : sample-004.c
/*
* 2019/07/12 sample-004.c
*/
/*
* 「順接」の繰返し
* A,B,C,D,E,F = (((((A,B),C),D),E),F)
* 6 行の命令は、順接を 5 回行ったと考える
*/
#include <stdio.h>
int main ( void ) {
printf ( "1 : Hello, World\n" );
printf ( "2 : Hello, World\n" );
printf ( "3 : Hello, World\n" );
printf ( "4 : Hello, World\n" );
printf ( "5 : Hello, World\n" );
printf ( "6 : Hello, World\n" );
return 0;
}
$ ./sample-004.exe 1 : Hello, World 2 : Hello, World 3 : Hello, World 4 : Hello, World 5 : Hello, World 6 : Hello, World $
Download : sample-005.c
/*
* 2019/07/12 sample-005.c
*/
/*
* 「順接」の繰返し
* ブロック( {, } ) を利用して明示的に記述
*/
#include <stdio.h>
int main ( void ) {
{
{
{
{
printf ( "1 : Hello, World\n" );
printf ( "2 : Hello, World\n" );
}
printf ( "3 : Hello, World\n" );
}
printf ( "4 : Hello, World\n" );
}
printf ( "5 : Hello, World\n" );
}
printf ( "6 : Hello, World\n" );
return 0;
}
$ ./sample-005.exe 1 : Hello, World 2 : Hello, World 3 : Hello, World 4 : Hello, World 5 : Hello, World 6 : Hello, World $
Download : sample-006.c
/*
* 2019/07/12 sample-006.c
*/
/*
* 「順接」の繰返し
* 同じ命令の繰返し
*/
#include <stdio.h>
int main ( void ) {
printf ( "Hello, World\n" ); /* 「Hello, World」を 6 度 */
printf ( "Hello, World\n" );
printf ( "Hello, World\n" );
printf ( "Hello, World\n" );
printf ( "Hello, World\n" );
printf ( "Hello, World\n" );
return 0;
}
$ ./sample-006.exe Hello, World Hello, World Hello, World Hello, World Hello, World Hello, World $
Download : sample-007.c
/*
* 2019/07/12 sample-007.c
*/
/*
* 命令列に名前を付ける (関数の作成)
*/
#include <stdio.h>
/*
命令の断片「printf ( "Hello, World\n" );」に printHello という名前を付ける
*/
void printHello(void) { /* 関数の定義 */
printf ( "Hello, World\n" ); /* 「Hello, World」を出力する関数 */
}
int main ( void ) {
printHello(); /* 元々あったものと同じ */
/* 命令は、「関数名」で「呼出し」可能 */
/* 表現が「短く」なった */
printf ( "Hello, World\n" );
printf ( "Hello, World\n" );
printf ( "Hello, World\n" );
printf ( "Hello, World\n" );
printf ( "Hello, World\n" );
return 0;
}
$ ./sample-007.exe Hello, World Hello, World Hello, World Hello, World Hello, World Hello, World $
Download : sample-008.c
/*
* 2019/07/12 sample-008.c
*/
/*
* 「関数の呼出し」の繰返し
*/
#include <stdio.h>
void printHello(void) {
printf ( "Hello, World\n" );
}
int main ( void ) {
printHello(); /* 一度定義した関数は何度でも呼出し可能 */
printHello();
printHello();
printHello();
printHello();
printHello();
return 0;
}
$ ./sample-008.exe Hello, World Hello, World Hello, World Hello, World Hello, World Hello, World $
Download : sample-009.c
/*
* 2019/07/12 sample-009.c
*/
/*
* 関数の本体には「命令列」が記述できる
*/
#include <stdio.h>
void printHello(void) {
printf ( "Hello, World\n" ); /* 「Hello, World」を出力する関数 */
}
void printTwoHello(void) { /* printHello を二度呼ぶ */
printHello(); /* 本体には、「命令列」でもよい */
printHello();
}
int main ( void ) {
printTwoHello(); /* printTwoHello() を三度呼ぶ */
printTwoHello(); /* 結果的に printHello() が六度呼ばれる */
printTwoHello(); /* 最終的に 「Hello, World」が六行出力される */
return 0;
}
A
$ ./sample-009.exe < sample-009.in Hello, World Hello, World Hello, World Hello, World Hello, World Hello, World $
Download : sample-010.c
/*
* 2019/07/12 sample-010.c
*/
/*
* 似た命令の関数化 [1]
*/
#include <stdio.h>
int main ( void ) {
printf ( "1 : Hello, World\n" ); /* 命令が異っている場合は.. */
printf ( "2 : Hello, World\n" );
printf ( "3 : Hello, World\n" );
printf ( "4 : Hello, World\n" );
printf ( "5 : Hello, World\n" );
printf ( "6 : Hello, World\n" );
return 0;
}
$ ./sample-010.exe 1 : Hello, World 2 : Hello, World 3 : Hello, World 4 : Hello, World 5 : Hello, World 6 : Hello, World $
Download : sample-011.c
/*
* 2019/07/12 sample-011.c
*/
/*
* 似た命令の関数化 [2] : 異る部分と同じ部分にわける
*/
#include <stdio.h>
int main ( void ) {
printf ( "1" ); /* 異る部分 */
printf ( " : Hello, World\n" ); /* 同じ部分 */
printf ( "2" );
printf ( " : Hello, World\n" );
printf ( "3" );
printf ( " : Hello, World\n" );
printf ( "4" );
printf ( " : Hello, World\n" );
printf ( "5" );
printf ( " : Hello, World\n" );
printf ( "6" );
printf ( " : Hello, World\n" );
return 0;
}
$ ./sample-011.exe 1 : Hello, World 2 : Hello, World 3 : Hello, World 4 : Hello, World 5 : Hello, World 6 : Hello, World $
Download : sample-012.c
/*
* 2019/07/12 sample-012.c
*/
/*
* 似た命令の関数化 [3] : 異る部分を「変数化」する事により、関数に出来る
*/
#include <stdio.h>
void printStringHello ( char *X ) {
printf ( X ); /* 異る部分が変数(X:仮引数)で共通化 */
/* 仮引数 X (の「値」)は、実引数置き変る */
printf ( " : Hello, World\n" ); /* 同じ部分 */
}
int main ( void ) {
printStringHello ( "1" ); /* 異る部分を「実引数」として指定 */
/* 呼び出された関数の中の仮引数の値を
関数の呼出し元で指定できる */
printStringHello ( "2" );
printStringHello ( "3" );
printStringHello ( "4" );
printStringHello ( "5" );
printStringHello ( "6" );
return 0;
}
$ ./sample-012.exe 1 : Hello, World 2 : Hello, World 3 : Hello, World 4 : Hello, World 5 : Hello, World 6 : Hello, World $
Download : sample-013.c
/*
* 2019/07/12 sample-013.c
*/
/*
* 似た命令の関数化 [4] : 引数の型
*/
#include <stdio.h>
void printCharHello ( char X ) { /* 変数の型を char 型に変更 */
putchar ( X ); /* X を「文字」出力 */
printf ( " : Hello, World\n" ); /* 同じ部分 */
}
void printCharHello ( char X ) { /* 変数の型を char 型に変更 */
int main ( void ) {
printCharHello ( '1' ); /* 引数も「文字」にする必要がある */
printCharHello ( '2' );
printCharHello ( '3' );
printCharHello ( '4' );
printCharHello ( '5' );
printCharHello ( '6' );
return 0;
}
$ ./sample-013.exe 1 : Hello, World 2 : Hello, World 3 : Hello, World 4 : Hello, World 5 : Hello, World 6 : Hello, World $
Download : sample-014.c
/*
* 2019/07/12 sample-014.c
*/
/*
* 似た命令の関数化 [5] : 引数の計算
*/
#include <stdio.h>
void printCharHello ( char X ) { /* 変数の型を char 型に変更 */
putchar ( X ); /* X を「文字」出力 */
printf ( " : Hello, World\n" ); /* 同じ部分 */
}
void printTwoCharHello ( char X ) {
printCharHello ( X ); /* 一度目は、引数をそのまま */
printCharHello ( X + 1 ); /* ニ度目は、引数の値の次の値を利用 */
/* '1' + 1 -> '2' */
/* '3' + 1 -> '4' */
/* '5' + 1 -> '6' */
}
int main ( void ) {
printCharTwoHello ( '1' ); /* 三度呼ぶと.. */
printCharTwoHello ( '3' );
printCharTwoHello ( '5' ); /* 六行.. */
return 0;
}
$ ./sample-014.exe $
Download : sample-015.c
/*
* 2019/07/12 sample-015.c
*/
#include <stdio.h>
/*
* check_star_char
*/
void check_star_char ( char ch ) {
if ( ch == '*' ) { /* ch の中身が '*' かどうかをチェック */
printf ( "これは「*」です\n" );
} else {
printf ( "これは「*」ではありません\n" );
}
}
/*
* main
*/
int main(void) {
check_star_char ( getchar() ); /* getchar() で文字を読込み、それを出力 */
return 0;
}
A
$ ./sample-015.exe < sample-015.in A これは「*」ではありません $
Download : sample-016.c
/*
* 2019/07/12 sample-016.c
*/
/*
* s_print.h の利用法
*
* 利用方法
* コンパイル
* cc -I ~/c/include sample-016.c
* cc -I ~/c/include -o sample-016.exe sample-016.o
* 実行
* ./sample-016.exe
*/
#include <stdio.h>
#include "s_print.h" /* s_print.h を利用する */
/*
*/
int main ( void ) {
printf ( "s_print_string で「文字列」を出力「" );
s_print_string ( "1" ); /* 文字列「1」を出力 */
printf ( "」\n" );
printf ( "s_print_int で「整数値」を出力「" );
s_print_int ( 1 ); /* 整数値「1」を出力 */
printf ( "」\n" );
printf ( "s_print_char で「文字」を出力「" );
s_print_char ( '1' ); /* 文字「1」を出力 */
printf ( "」\n" );
return 0;
}
$ ./sample-016.exe s_print_string で「文字列」を出力「1」 s_print_int で「整数値」を出力「1」 s_print_char で「文字」を出力「1」 $
Download : sample-017.c
/*
* 2019/07/12 sample-017.c
*/
/*
* s_input.h の利用法 (1)
*
* 利用方法
* コンパイル
* cc -I ~/c/include sample-017.c
* cc -I ~/c/include -o sample-017.exe sample-017.o
* 実行
* ./sample-017.exe
*/
#include <stdio.h>
#include "s_print.h" /* s_print.h を利用する */
#include "s_input.h" /* s_input.h を利用する */
/*
*/
int main ( void ) {
printf ( "文字列を入力して改行してください : " );
s_print_string ( s_input_string() );
printf ( "\n--------------------\n" );
printf ( "整数値を入力して改行してください : " );
s_print_int ( s_input_int() );
printf ( "\n--------------------\n" );
printf ( "文字を一文字入力して改行してください : " );
s_print_char ( s_input_char() );
printf ( "\n--------------------\n" );
return 0;
}
abc 123 X
$ ./sample-017.exe < sample-017.in 文字列を入力して改行してください : abc abc -------------------- 整数値を入力して改行してください : 123 123 -------------------- 文字を一文字入力して改行してください : X X -------------------- $
Download : sample-018.c
/*
* 2019/07/12 sample-018.c
*/
/*
* s_input.h の利用法 (2)
*
* 利用方法
* コンパイル
* cc -I ~/c/include sample-018.c
* cc -I ~/c/include -o sample-018.exe sample-018.o
* 実行
* ./sample-018.exe
*/
#include <stdio.h>
#include "s_print.h" /* s_print.h を利用する */
#include "s_input.h" /* s_input.h を利用する */
/*
* +1 した結果は、型によって異る。
*/
int main ( void ) {
printf ( "文字列を入力して改行してください。+1 した結果を出力します。: " );
s_print_string ( s_input_string() + 1 );
printf ( "\n--------------------\n" );
printf ( "整数値を入力して改行してください。+1 した結果を出力します。 : " );
s_print_int ( s_input_int() + 1 );
printf ( "\n--------------------\n" );
printf ( "文字を一文字入力して改行してください。+1 した結果を出力します。 : " );
s_print_char ( s_input_char() + 1 );
printf ( "\n--------------------\n" );
return 0;
}
abc 123 X
$ ./sample-018.exe < sample-018.in 文字列を入力して改行してください。+1 した結果を出力します。: abc bc -------------------- 整数値を入力して改行してください。+1 した結果を出力します。 : 123 124 -------------------- 文字を一文字入力して改行してください。+1 した結果を出力します。 : X Y -------------------- $
Download : sample-019.c
/*
* 2019/07/12 sample-019.c
*/
/*
* 型の違い
*
* 利用方法
* コンパイル
* cc -I ~/c/include sample-019.c
* cc -I ~/c/include -o sample-019.exe sample-019.o
* 実行
* ./sample-019.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* main 関数
*/
int main ( void ) {
/*
* 型が違っても表示は同じ
*/
s_print_string ( "整数 : " );
s_print_int ( 9 );
s_print_newline();
s_print_string ( "文字 : " );
s_print_char ( '9' );
s_print_newline();
s_print_string ( "文字列 : " );
s_print_string ( "9" );
s_print_newline();
/*
* 整数の場合の +1
*/
s_print_string ( "整数の計算 : 9 + 1 = " );
s_print_int ( 9 + 1 );
s_print_newline();
/*
* 文字の場合の +1
*/
s_print_string ( "文字の計算 : '9' + 1 = " );
s_print_char ( '9' + 1 );
s_print_newline();
/*
* 文字列の場合の +1
*/
s_print_string ( "文字の計算 : \"9\" + 1 = " );
s_print_string ( "9" + 1 );
s_print_newline();
/*
* 型によって、計算結果が異る
*/
return 0;
}
$ ./sample-019.exe 整数 : 9 文字 : 9 文字列 : 9 整数の計算 : 9 + 1 = 10 文字の計算 : '9' + 1 = : 文字の計算 : "9" + 1 = $
Download : sample-020.c
/*
* 2019/07/12 sample-020.c
*/
/*
* 整数の四則計算式
*
* 利用方法
* コンパイル
* cc -I ~/c/include sample-020.c
* cc -I ~/c/include -o sample-020.exe sample-020.o
* 実行
* ./sample-020.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* main 関数
*/
int main ( void ) {
/*
* 加法(足し算)
*/
s_print_string ( "12 + 5 = " );
s_print_int ( 12 + 5 ); /* 整数の 12 と 5 を加える */
s_print_newline();
/*
* 減法(引き算)
*/
s_print_string ( "12 - 5 = " );
s_print_int ( 12 - 5 ); /* 整数の 12 から 5 を引く */
s_print_newline();
/*
* 乗法(かけ算)
*/
s_print_string ( "12 * 5 = " );
s_print_int ( 12 * 5 ); /* 整数の 12 に 5 をかける */
s_print_newline();
/*
* 商法(割り算)
*/
s_print_string ( "12 / 5 = " );
s_print_int ( 12 / 5 ); /* 整数の 12 を 5 で割る */
s_print_newline();
/*
* 式の優先順位やかっこも利用可能
*/
s_print_string ( "1 + 2 * 3 = " );
s_print_int ( 1 + 2 * 3 ); /* かけ算が優先される */
s_print_newline();
s_print_string ( "(1 + 2) * 3 = " );
s_print_int ( (1 + 2) * 3 ); /* かっこの中の計算が優先される */
s_print_newline();
return 0;
}
$ ./sample-020.exe 12 + 5 = 17 12 - 5 = 7 12 * 5 = 60 12 / 5 = 2 1 + 2 * 3 = 7 (1 + 2) * 3 = 9 $
Download : sample-021.c
/*
* 2019/07/12 sample-021.c
*/
/*
* 文字列の演算式
*
* 利用方法
* コンパイル
* cc -I ~/c/include sample-021.c
* cc -I ~/c/include -o sample-021.exe sample-021.o
* 実行
* ./sample-021.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* main 関数
*/
int main ( void ) {
/*
* 文字列への加法
*/
s_print_string ( "\"abc\" + 1 = " );
s_print_string ( "abc" + 1 ); /* 文字列が短くなる */
s_print_newline();
/*
* 先頭の文字の取出し
*/
s_print_string ( "*\"abc\" = " );
s_print_char ( *"abc" ); /* 先頭の文字が出て来る */
s_print_newline();
return 0;
}
$ ./sample-021.exe "abc" + 1 = bc *"abc" = a $
Download : sample-022.c
/*
* 2019/07/12 sample-022.c
*/
/*
* 関数呼出しを含む形の「式」
*
* 利用方法
* コンパイル
* cc -I ~/c/include sample-022.c
* cc -I ~/c/include -o sample-022.exe sample-022.o
* 実行
* ./sample-022.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* main 関数
*/
int main ( void ) {
/*
* 加法(足し算)
*/
s_print_string ( "12 + 5 = " );
s_print_int ( 12 + 5 ); /* 整数の 12 と 5 を加える */
s_print_newline();
/*
* 減法(引き算)
*/
s_print_string ( "12 - 5 = " );
s_print_int ( 12 - 5 ); /* 整数の 12 から 5 を引く */
s_print_newline();
/*
* 乗法(かけ算)
*/
s_print_string ( "12 * 5 = " );
s_print_int ( 12 * 5 ); /* 整数の 12 に 5 をかける */
s_print_newline();
/*
* 商法(割り算)
*/
s_print_string ( "12 / 5 = " );
s_print_int ( 12 / 5 ); /* 整数の 12 を 5 で割る */
s_print_newline();
return 0;
}
$ ./sample-022.exe 12 + 5 = 17 12 - 5 = 7 12 * 5 = 60 12 / 5 = 2 $
Download : sample-023.c
/*
* 2019/07/12 sample-023.c
*/
/*
* 関数の値 [1]
*
* 利用方法
* コンパイル
* cc -I ~/c/include sample-023.c
* cc -I ~/c/include -o sample-023.exe sample-023.o
* 実行
* ./sample-023.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* int zero(void)
* 常に整数値「0」を返す定数関数
*/
int zero(void) {
return 0; /* 返す値(0)を return 命令で返す */
/* 関数は return 命令を実行すると、その時点で終了する */
/* もし、この部分に命令があったとしても、それは実行されない */
}
/*
* main 関数
*/
int main ( void ) {
/*
* 返り値を持つ関数の呼出し
*/
s_print_string ( "関数 zero() の呼出し\n" );
s_print_string ( "zero() = " );
s_print_int ( zero() ); /* 関数 zero() を呼出し、その値を出力 */
s_print_newline();
/*
* 返り値を式の一部として利用できる
*/
s_print_string ( "関数 zero() を二度呼出す\n" );
s_print_string ( "zero() + zero() = " );
s_print_int ( zero() + zero() ); /* 0+0 = 0 なので結果は変らず */
s_print_newline();
return 0;
}
$ ./sample-023.exe 関数 zero() の呼出し zero() = 0 関数 zero() を二度呼出す zero() + zero() = 0 $
Download : sample-024.c
/*
* 2019/07/12 sample-024.c
*/
/*
* 関数の値 [2]
*
* 利用方法
* コンパイル
* cc -I ~/c/include sample-024.c
* cc -I ~/c/include -o sample-024.exe sample-024.o
* 実行
* ./sample-024.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* int inc ( int number )
* 引数で指定された整数値に 1 を加えた値を返す
*/
int inc( int number ) {
return number + 1; /* return 命令の後の式は計算され、その結果が返る */
}
/*
* main 関数
*/
int main ( void ) {
/*
* 値を持つ関数の呼出し
*/
s_print_string ( "関数 inc( 3 ) の呼出し\n" );
s_print_string ( "inc ( 3 ) = " );
s_print_int ( inc( 3 ) ); /* 関数 inc に実引数 3 を与えて呼出し、その値を出力 */
s_print_newline();
s_print_string ( "関数 inc( -123 ) の呼出し\n" );
s_print_string ( "inc ( -123 ) = " );
s_print_int ( inc( -123 ) );
s_print_newline();
return 0;
}
$ ./sample-024.exe 関数 inc( 3 ) の呼出し inc ( 3 ) = 4 関数 inc( -123 ) の呼出し inc ( -123 ) = -122 $
Download : sample-025.c
/*
* 2019/07/12 sample-025.c
*/
/*
* 関数の値 [3]
*
* 利用方法
* コンパイル
* cc -I ~/c/include sample-025.c
* cc -I ~/c/include -o sample-025.exe sample-025.o
* 実行
* ./sample-025.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* int add ( int a, int b )
* 引数で指定された二つの整数値の値の和を返す関数
*/
int add( int a, int b ) {
return a + b;
}
/*
* main 関数
*/
int main ( void ) {
/*
* 値を持つ関数の呼出し
*/
s_print_string ( "関数 add( 3, 8 ) の呼出し\n" );
s_print_string ( "add ( 3, 8 ) = " );
s_print_int ( add( 3, 8 ) ); /* 関数 add に二つの実引数 3 と 8 を与えて呼出し、その値を出力 */
s_print_newline();
s_print_string ( "関数 add( 256, -123 ) の呼出し\n" );
s_print_string ( "add ( 256, -123 ) = " );
s_print_int ( add( 256, -123 ) );
s_print_newline();
return 0;
}
$ ./sample-025.exe 関数 add( 3, 8 ) の呼出し add ( 3, 8 ) = 11 関数 add( 256, -123 ) の呼出し add ( 256, -123 ) = 133 $
Download : sample-026.c
/*
* 2019/07/12 sample-026.c
*/
/*
* 関数の値 [4]
*
* 利用方法
* コンパイル
* cc -I ~/c/include sample-026.c
* cc -I ~/c/include -o sample-026.exe sample-026.o
* 実行
* ./sample-026.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* int myabs ( int number )
* 引数で指定された整数値の絶対値を返す
*/
int myabs ( int number ) {
/* 条件分岐 ( if 文 ) を利用して、返す値を変更する事ができる */
if ( number >= 0 ) { /* 引数の値が非負であれば.. */
return number; /* その値をそのまま返す */
} else { /* そうでなければ (負なので..) 符号を変更して返す */
return number * (-1); /* 実は、「 - number 」と書いても良い */
}
/* ここには何もいらない ( if でどちらに行っても return 文に当る ) */
}
/*
* main 関数
*/
int main ( void ) {
/*
* 条件判断をする関数
*/
s_print_string ( "整数値を入力してください。その絶対値を表示します : " );
s_print_int ( myabs ( s_input_int() ) );
s_print_newline();
return 0;
}
-12 89
$ ./sample-026.exe < sample-026.in 整数値を入力してください。その絶対値を表示します : -12 12 $
Download : sample-027.c
/*
* 2019/07/12 sample-027.c
*/
/*
* 関数の値 [5]
*
* 利用方法
* コンパイル
* cc -I ~/c/include sample-027.c
* cc -I ~/c/include -o sample-027.exe sample-027.o
* 実行
* ./sample-027.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* int sum ( int number )
* 1 から、引数で指定された整数値迄の総和 : 1 + 2 + .. + number を返す
*/
int sum ( int number ) {
if ( number <= 0 ) { /* number が 0 の値は.. */
return 0; /* 0 を返す */
/* 「number == 0」でなく「number <= 0」なのは
予防的(危険を予め避ける)なプログラミング */
} else { /* そうでなければ.. */
return number + sum ( number - 1 );
/* 再帰呼出しで計算 */
}
/*
* もちろん、再帰呼出しを利用せず、
* いきなり return number * (number+1) / 2 でも良いが..
*/
}
/*
* main 関数
*/
int main ( void ) {
/*
* 再帰呼出しをする計算
*/
s_print_string ( "整数値を入力してください。\n" );
s_print_string ( "1 からその数までの総和を計算します : " );
s_print_int ( sum ( s_input_int() ) );
s_print_newline();
s_print_string ( "\n--------------------------------------------\n\n" );
s_print_string ( "もう一つ整数値を入力してください。\n" );
s_print_string ( "1 からその数までの総和を計算します : " );
s_print_int ( sum ( s_input_int() ) );
s_print_newline();
return 0;
}
10 100
$ ./sample-027.exe < sample-027.in 整数値を入力してください。 1 からその数までの総和を計算します : 10 55 -------------------------------------------- もう一つ整数値を入力してください。 1 からその数までの総和を計算します : 100 5050 $
/*
* 20190712-01-QQQQ.c
*
* 二つの整数の積を返す関数
*
* コンパイル :
* cc -I ~/c/include -c 20190712-01-QQQQ.c
* cc -o 20190712-01-QQQQ.exe 20190712-01-QQQQ.o
* 実行 :
* ./20190712-01-QQQQ.exe
*
*/
#include <stdio.h>
#include "s_print.h" /* s_print_int を利用するので.. */
/*
* int imul ( int a, int b )
* int a : かけられる数
* int b : かける数
* 返り値 : a と b の積
*/
int imul ( int a, int b ) {
/* 関数 y = f(a,b) = a * b となる関数 f に imul という名前を付ける */
return a * b; /* 「return f(a,b);」 を書く */
}
/*
* main
*/
int main( void )
{
s_print_int ( 2 );
s_print_string ( " と、 " );
s_print_int ( 3 );
s_print_string ( " の積は " );
s_print_int ( imul( 2, 3 ) );
s_print_string ( " です。\n" );
s_print_int ( 12 );
s_print_string ( " と、 " );
s_print_int ( 78 );
s_print_string ( " の積は " );
s_print_int ( imul( 12, 78 ) );
s_print_string ( " です。\n" );
return 0;
}
/*
* 20190712-02-QQQQ.c
*
* 自然数の階乗を返す関数
*
* コンパイル :
* cc -I../include -c 20190712-02-QQQQ.c
* cc -o 20190712-02-QQQQ.exe 20190712-02-QQQQ.o
* 実行 :
* ./20190712-02-QQQQ.exe
*
*/
#include <stdio.h>
#include "s_print.h" /* s_print_int を利用するので.. */
/*
* int factrial ( int n )
* int n : 階乗を計算する自然数
* 返り値 : n! ( n の階乗 )
* n! = n * (n-1) * ... * 2 * 1
* 5! = 5 * 4 * .. * 2 * 1
* 5! = 5 * 4 * 3 * 2 * 1
* = 120
* 1 ( n が 1 の時 )
* n! = {
* n * ( (n-1)! ) ( other )
*
* 帰納的定義 : n! の値を定義するために (n-1)! の値を利用している
* cf. 数学的帰納法
* 「任意に自然数 n に対して、命題 P(n) が成立する」事を証明したい
* 1) P(1) が成立する事
* 2) P(k) が成立すれば P(k+1)が成立する事
* の二つを示す(事で、「証明」できた事にする..という方針..)
*/
int factrial ( int n ) {
if ( n <= 0 ) { /* 0!, 負の数の階乗は、取り敢えず 1 にする */
return 1; /* 特に 「0! = 1」に注意 */
} else { /* n が正の時は、「n! = n * (n-1)!」となるので.. */
return n * factrial ( n - 1 ); /* 自分自身の定義の中で自分自身を呼ぶ */
/* => 再帰呼び出し */
/* C 言語では「再帰呼び出し」が許されている */
/* => 何も悩む必要はない */
}
}
/*
* main
*/
int main( void )
{
s_print_int ( 3 );
s_print_string ( " の階乗の値は " );
s_print_int ( factrial ( 3 ) );
s_print_string ( " になります。\n" );
s_print_int ( 5 );
s_print_string ( " の階乗の値は " );
s_print_int ( factrial ( 5 ) );
s_print_string ( " になります。\n" );
return 0;
}
#include <stdio.h>
#include "s_print.h"
/*
関数 : square
定義域 : 整数 => int
値域 : 整数 => int
対応関係 : y = x^2
*/
int square ( int x ) { /* 関数 square は int 型の値 x から int 型の値を計算して返す */
return x * x; /* 関数の値 y は x * x = x^2 で計算される事を示す */
/* x * x の値計算し、それを、関数の値 (y) とする */
}
/*
main 関数も、(引数はともかく..) int 型の値域を持つ関数
*/
int main( int argc, char *argv[] ) {
s_print_string ( "3^2 = " ); /* 「3^2 = 」を表示 */
s_print_int ( square ( 3 ) ); /* square(3) が 3^2 を計算して返すので.. 「9」*/
s_print_string ( "\n" ); /* 改行 */
return 0;
}
#include <stdio.h>
#include "s_print.h"
/*
関数 : inc
定義域 : 整数 => int
値域 : 整数 => int
対応関係 : y = x + 1
y = f(x) f(x) が x を含む計算式の時
これを実現する C の関数の定義は
return f(x)
となる
*/
int inc ( int x ) { /* 関数 inc は int 型の値 x から int 型の値を計算して返す */
return x + 1; /* 関数の値 y は x + 1 で計算される事を示す */
/* x + 1 の値計算し、それを、関数の値 (y) とする */
}
/*
main 関数も、(引数はともかく..) int 型の値域を持つ関数
*/
int main( int argc, char *argv[] ) {
s_print_string ( "3 + 1 = " ); /* 「3 + 1 = 」を表示 */
s_print_int ( inc ( 3 ) ); /* inc(3) が 3+1 を計算して返すので.. 「4」*/
s_print_string ( "\n" ); /* 改行 */
return 0;
}
#include <stdio.h>
#include "s_print.h"
/*
関数 : 定数値関数 (ten)
値域 : 整数 => int
対応関係 : 常に 10 を返す
*/
int ten ( void ) { /* 関数 ten は int 型の値を返す。引数はない */
/* void (空虚) は、「引数が無い」事を示す */
return 10; /* 定数値として常に 10 を返す */
}
/*
main 関数も、(引数はともかく..) int 型の値域を持つ関数
*/
int main( int argc, char *argv[] ) {
s_print_string ( "10 = " ); /* 「10 = 」を表示 */
s_print_int ( ten () ); /* 関数 ten の後ろは 「()」[「(void)」でない] */
s_print_string ( "\n" ); /* 改行 */
return 0;
}
#include <stdio.h>
#include "s_print.h"
/*
関数 : 定数値関数 (foo)
返す値が無い場合は、関数の前に void を付ける
*/
void foo ( void ) { /* 関数 foo は void 型の値を返す。=> 返す値が無い */
/* <= return 命令も存在しない */
/* 実は、「return ;」、つまり return の後ろの式を書かない表現もある */
/* !! return には、「関数の値を決める」機能と、 */
/* !! ここで関数を終了させるという機能の二つがある */
}
/*
main 関数も、(引数はともかく..) int 型の値域を持つ関数
*/
int main( int argc, char *argv[] ) {
s_print_string ( "foo を呼び出してみたが.." ); /* 「10 = 」を表示 */
foo (); /* 関数 foo は値を返さないので、他の関数の引数になれない */
s_print_string ( "\n" ); /* 改行 */
return 0;
}
#include <stdio.h>
#include "s_print.h"
/*
関数 : 値の無い関数 [2] (bar)
返す値が無い場合は、関数の前に void を付ける
*/
void bar ( void ) { /* 関数 bar は foo と同様返す値が無い */
printf ( "Hello, World\n" ); /* <= 値を返さない(return 命令がない) が
他の関数を呼び出す出す事はできる */
/* => 結果的に、「画面に『Hello World』と表示する」という
「副作用」を起こす事がきる */
/* 関数は「値を計算する」という機能が、
「主作用」 */
}
/*
main 関数も、(引数はともかく..) int 型の値域を持つ関数
*/
int main( int argc, char *argv[] ) {
s_print_string ( "bar を呼び出しすと.." ); /* 「10 = 」を表示 */
bar (); /* 関数 bar は関数としては意味がないが、副作用を起こすという「意味」がある */
s_print_string ( "\n" ); /* 改行 */
return 0;
}
#include <stdio.h>
#include "s_print.h"
/*
関数 : add ( 引数が二つある関数)
定義域 : 整数 x 整数 (直積空間) => int
値域 : 整数 => int
対応関係 : z = f(x,y) = x + y
*/
int add ( int x, int y ) {
/* 関数 add は int 型の二つの値 x, y から int 型の値を計算して返す */
/* int x int という直積集合の要素<x,y>を定義域にしている */
/* => 後期には、C 言語で直積空間(に相当するもの)を扱う方法を学ぶ */
return x + y; /* f(x,y) = x+y : 二変数関数.. */
}
/*
main 関数も、(引数はともかく..) int 型の値域を持つ関数
*/
int main( int argc, char *argv[] ) {
s_print_string ( "3 + 2 = " );
s_print_int ( add ( 3, 2 ) );
s_print_string ( "\n" );
return 0;
}
#include <stdio.h>
#include "s_print.h"
/*
関数 : iabs
定義域 : 整数 => int
値域 : 整数 => int
x (x>=0)
対応関係 : y = |x| ={
-x (= (-1)*x) (other: x<0)
*/
int iabs ( int x ) {
if ( x >= 0 ) { /* x が非負の時 */
return x; /* x >= 0 の命令を実行*/
} else {
return -x; /* (-1)*x */ /* x < 0 の時の命令を実行 */
}
/* 実行する命令には。二つの可能性があり、
引数で与えられた x の値によって、どちらか
一方を実行したい */
/* 条件によって、二つの命令のうち、どちらか一方を実行したい場合
=> if 構文を利用する
if ( 条件 ) {
条件が成立した時の命令列
} else {
条件が不成の時(上記の場合以外の時)の命令列
}
*/
}
/*
main 関数も、(引数はともかく..) int 型の値域を持つ関数
*/
int main( int argc, char *argv[] ) {
s_print_string ( "|3| = " );
s_print_int ( iabs ( 3 ) );
s_print_string ( "\n" );
s_print_string ( "|-12| = " );
s_print_int ( iabs ( -12 ) );
s_print_string ( "\n" );
return 0;
}
#include <stdio.h>
#include "s_print.h"
/*
関数 :
定義域 : 整数 => int
値域 : 整数 => int
x (x>=0)
対応関係 : y = |x| ={
-x (= (-1)*x) (other: x<0)
*/
int iabs ( int x ) {
if ( x >= 0 ) { /* x が非負の時 */
return x; /* x >= 0 の命令を実行*/
} else {
return -x; /* (-1)*x */ /* x < 0 の時の命令を実行 */
}
/* 実行する命令には。二つの可能性があり、
引数で与えられた x の値によって、どちらか
一方を実行したい */
/* 条件によって、二つの命令のうち、どちらか一方を実行したい場合
=> if 構文を利用する
if ( 条件 ) {
条件が成立した時の命令列
} else {
条件が不成の時(上記の場合以外の時)の命令列
}
*/
}
/*
main 関数も、(引数はともかく..) int 型の値域を持つ関数
*/
int main( int argc, char *argv[] ) {
s_print_string ( "|3| = " );
s_print_int ( iabs ( 3 ) );
s_print_string ( "\n" );
s_print_string ( "|-12| = " );
s_print_int ( iabs ( -12 ) );
s_print_string ( "\n" );
return 0;
}
#include <stdio.h>
#include "s_print.h"
/*
関数 log2 : 整数型の log_2 の計算
定義域と値域は整数
log2(n)=k 2^{k-1} < n <= 2^{k+1}
例
log2(10)=4
帰納的定義
0 (n=1)
log2(n)={
log2(n/2)+1 (other)
*/
int log2 ( int n ) {
if ( n <= 0 ) {
return 0;
} else {
return log2(n/2) + 1;
}
}
/*
main 関数も、(引数はともかく..) int 型の値域を持つ関数
*/
int main( int argc, char *argv[] ) {
s_print_string ( "log2(10) = " );
s_print_int ( log2 ( 10 ) );
s_print_string ( "\n" );
return 0;
}
[前回(2019/07/05)の復習
前回(2019/07/05)の内容 (二週目に入った)
知識も技術も習得のためには、繰り返しが必要
講義 => 演習 => 復習をする
知識 : 繰り返しにコストがかからない(頭の中でできる)
技術 : 作業を伴うので、繰り返すのは結構大変
=> 講義(演習)の中で、繰り返しを強制する => 繰り返し学習をする
<= 先週から、繰り返しの二週目に入る
「Hello, World」 again (お呪いが減った)
[hello.c]
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
#include <stdio.h>
int main(int argc, char *argv[]) {
printf ( "Hello, World\n" );
return 0;
}
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
初回 : いろいろなお呪いがあった
=> お呪いはお呪いのまま、printf の部分に着目して議論
前回 : お呪いの解説
#incldue => 他のファイルを読み込んでいる
stdio.h => 標準入出力関数の関数宣言(等)が入っている
# 少なくても printf 関数のプロトタイプ宣言が入っている
# => 標準入出力関数(printf,getchar,putchar)を使う時には必要
main 関数
C のプログラムには必ず必要
# C プログラムは、関数の集まりとして作成できる
# <= その中の一つが main 関数であり、そこからプログラムがスタート
# => main 以外の関数は、main から直接あるいは間接的に呼び出される
先頭の int (main の前) と、最後の return 0; は、このプログラムが、
システムに「整数型の値(エラーコード)を返す」事意味している
その値(エラーコード)が 0 (エラーでない事を表す)である
「システムにエラーコードを返す : main 関数」
引数の argc, argv
それぞれ、コマンドライン引数の個数とその値(文字列)を意味する
御呪いでない部分
C 言語で作られた完全なプログラム
=> これを雛形にして、いろいろなプログラムを作成する事ができる
C 言語の最初のサンプルプログラム
=> プログラムのコンパイルやリンク、実行の方法を学ぶ
printf 関数の機能(引数に与えられた文字列を画面に表示する)
=> C 言語で利用できる基本機能(標準ライブラリ)の API を学ぶ最初の例
順接
「printf 関数を呼ぶ」(命令を実行する)と、メッセージが表示されるという「効果」がある(hello.c)
この printf を並べる(命令をならべる)と、その命令が、「書かれた順に実行」される
=> C 言語が持つ「順接」という「表現方法」の効果
# 関数の定義順は、関数の実行順序とは無関係(関数定義は命令じゃない)
=> 有限の結果を成したい場合は、
その結果を導くような命令をならべる(呼び出す関数の選択と順接)だけで実現可能
cf. 自分の名前を 100 回書く
=> 今 : 再帰(繰り返し)で行う
=> 当時 : 命令を 100 回書けば、実現できる
「命令を組み合わせる(制御構造)」:プログラムの基本
順接は(基本となる三つの)制御構造の一つ
=> 残りの制御構造(条件分岐[if 構文]/繰り返し[再帰])と合わせて、万能になる
==
[今日の内容]
関数の作り方と使い方 again
関数とは
[数学(入門 A)] 定義域と値域があり、それぞれの集合の要素間の対応関係で、定義域の値が一つ定まれば、
必ず、値域の値が定まるもの
C 言語でも基本、関数の考え方は同じ
例 : y = x^2 を計算する関数 square => p-001.c
C 言語でも「関数」が定義できる
定義域 : 引数の型
値域 : 関数の値型
対関係 : return の所に値となる計算式を書く
一般に y=f(x) [f(x) は x の式] となる C 言語での関数の定義
!!! function => 関数 / 機能
値域型 関数名(定義域の型 その値を持つ変数) {
return 値を計算する式;
}
引数が無い場合は、定義域がないので、引数は void と宣言して、呼び出し時は、
引数を記述しない。
一方、「値を持たない『関数』」も作れて、その場合は、「値の型」の所に「void」と書く
また、値を書かない関数は、他の関数の引数にできないので、直接「関数名(引数);」の形
で呼び出す(必要がある..)
一般に、値を返さない関数は、「関数(何らかの計算を行い、その結果を値として返す)」として
主作用は、存在しないが、副作用を記述できるので。それを目的として、
作る意味がある
cf. 関数の導入
printf ( .. ) => 副作用を行う「関数」
副作用に対して、名前を付ける事が可能
=> 値を返さない関数(void 型)を導入した
「関数」の定義の仕方
1. (純粋に..)数学的な関数 ( y = f(x) を計算する関数 ) を定義する場合
値域の型 関数名(定義域の型 x) {
return f(x);
}
s_prnit_xxx( 関数名(数値) ) => 数値から関数の値を計算した結果が表示される
2. 副作用を持つ命令列に名前をつけて(その副作用を利用するために)関数とする場合
void 関数名(void) {
副作用を持つ命令列
}
!! プログラムのまとまった一部に「名前」をつけ、
!! その名前を指定する事により、その部分を「再利用」できる
!! 事が大事
!! C 言語における「関数」は、一般の言語の「モジュール(部品)」に相当
[拡張]
引数は、複数指定する事が可能で、
個々の引数には、別の名前(仮引数変数名)を付け、それぞれに型を指定する
関数としては、 n 引数関数 or n 個の直積集合の要素を一つが定義域になる
条件分岐 : 条件によって、異なる複数の命令のいずれかを実行する「構文(命令の組み合わせを表現する方法)」
C 言語では、条件分岐(の表現方法の一つ)として「if 構文」がある
if ( 条件 ) {
条件が成立した時に実行する命令列
} else {
条件が不成立の時に実行する命令列
}
!!! 後期 : if 構文以外の条件分岐の記述方法がある...
!!! 但し、任意の条件分岐は、if 構文の組み合わせで実現可能
繰り返し : 同じ命令を何度も繰り返し実行する構文
!!! 「何度も繰り返す」.. 「具体的は何回 ??」
!!! => 実際に「繰り返し」を行う場合は、「繰り返しが終わった」という条件がわかる必要がある
C 言語では(実は普通に繰り返しを行う構文が他にあるが..)、再帰呼び出しで、実現する
例:
n! = n * (n-1) * .. * 2 * 1
=> n の値によって、掛け算の個数が異なる
例 :
3! = 3 * 2 * 1 => 2 回 ( 3-1 ) 回の掛け算
5! = 5 * 4 * 3 * 2 * 1 =. 4 ( 5-1 ) 回の掛け算
<= 記述された命令の長さと、実行される命令の個数(長さ)が異なる
cf. 順接は、記述された命令の長さと、実行される命令の個数(長さ)が同じ
=> 原理的に、有限の記述で無限の種類の命令が実行できる
cf. n! は n の値によって、異なる個数の命令が実行されている
再帰の場合は、基本、繰り返せる命令の種類は一定
関数 f() を、終了条件になるまで、繰り返すための再帰的関数定義
rec_f(n) {
if ( n に関する終了条件 ) {
終了処理
} else {
f() ; 繰り返したい事
rec_f ( next (n) ); n を次の状態にして再帰呼び出し
# next n は、n が終了条件を満たすまで、「減らす」作業
# 自然数なら -1 する => 1 (終了条件を満たす) に近づける
# 文字列なら +1 する => "" (終了条件を満たす) に近づける
}
}
与えられた問題の解を、再帰的定義に変換できれば、
それは、C 言語の再帰呼び出しで実現できる
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20190712-01.c
/*
* 20190712-01-QQQQ.c
*
* 二つの整数の積を返す関数
*
* コンパイル :
* cc -I ~/c/include -c 20190712-01-QQQQ.c
* cc -o 20190712-01-QQQQ.exe 20190712-01-QQQQ.o
* 実行 :
* ./20190712-01-QQQQ.exe
*
*/
#include <stdio.h>
#include "s_print.h" /* s_print_int を利用するので.. */
/*
* int imul ( int a, int b )
* int a : かけられる数
* int b : かける数
* 返り値 : a と b の積
*/
int imul ( int a, int b ) {
/*
** この部分を完成させなさい
*/
}
/*
* main
*/
int main( void )
{
s_print_int ( 2 );
s_print_string ( " と、 " );
s_print_int ( 3 );
s_print_string ( " の積は " );
s_print_int ( imul( 2, 3 ) );
s_print_string ( " です。\n" );
s_print_int ( 12 );
s_print_string ( " と、 " );
s_print_int ( 78 );
s_print_string ( " の積は " );
s_print_int ( imul( 12, 78 ) );
s_print_string ( " です。\n" );
return 0;
}
$ ./20190712-01-QQQQ.exe 2 と、 3 の積は 6 です。 12 と、 78 の積は 936 です。 $
Download : 20190712-02.c
/*
* 20190712-02-QQQQ.c
*
* 自然数の階乗を返す関数
*
* コンパイル :
* cc -I../include -c 20190712-02-QQQQ.c
* cc -o 20190712-02-QQQQ.exe 20190712-02-QQQQ.o
* 実行 :
* ./20190712-02-QQQQ.exe
*
*/
#include <stdio.h>
#include "s_print.h" /* s_print_int を利用するので.. */
/*
* int factrial ( int n )
* int n : 階乗を計算する自然数
* 返り値 : n! ( n の階乗 )
*/
int factrial ( int n ) {
if ( n <= 0 ) { /* 0!, 負の数の階乗は、取り敢えず 1 にする */
return 1; /* 特に 「0! = 1」に注意 */
} else { /* n が正の時は、「n! = n * (n-1)!」となるので.. */
/*
** この部分を完成させなさい
*/
}
}
/*
* main
*/
int main( void )
{
s_print_int ( 3 );
s_print_string ( " の階乗の値は " );
s_print_int ( factrial ( 3 ) );
s_print_string ( " になります。\n" );
s_print_int ( 5 );
s_print_string ( " の階乗の値は " );
s_print_int ( factrial ( 5 ) );
s_print_string ( " になります。\n" );
return 0;
}
$ ./20190712-02-QQQQ.exe 3 の階乗の値は 6 になります。 5 の階乗の値は 120 になります。 $
Download : 20190712-03.c
/*
* 20190712-03-QQQQ.c
*
* 二つの整数の最大公約数を返す
*
* コンパイル :
* cc -I../include -c 20190712-03-QQQQ.c
* cc -o 20190712-03-QQQQ.exe 20190712-03-QQQQ.o
* 実行 :
* ./20190712-03-QQQQ.exe
*
*/
#include <stdio.h>
#include "s_print.h" /* s_print_int を利用するので.. */
/*
* int euclid ( int a, int b )
* int a : 非負の整数
* int b : 非負の整数
* 返り値 : a と b の最大公約数を返す
*/
int euclid ( int a, int b ) {
if ( b == 0 ) { /* 任意の数 a と 0 の最大公約数 (a,0) は a となる */
return a;
} else { /* b が 0 でない時 (a,b) = (b,a%b) となる */
/*
** この部分を完成させなさい
*/
}
}
/*
* main
*/
int main( void )
{
s_print_int ( 12 );
s_print_string ( " と、 " );
s_print_int ( 18 );
s_print_string ( " の最大公約数は " );
s_print_int ( euclid( 12, 18 ) );
s_print_string ( " です。\n" );
s_print_int ( 1111 );
s_print_string ( " と、 " );
s_print_int ( 111111 );
s_print_string ( " の最大公約数は " );
s_print_int ( euclid( 1111, 111111 ) );
s_print_string ( " です。\n" );
return 0;
}
$ ./20190712-03-QQQQ.exe 12 と、 18 の最大公約数は 6 です。 1111 と、 111111 の最大公約数は 11 です。 $