Download : sample-001.c
/* * 2020/11/13 sample-001.c */ #include <stdio.h> #include "s_memory.h" /* memory モデルを理解するための関数定義 */ /* * */ int main ( void ) { /* * メモリの操作 ( 情報の記録 : set_memory_value_at ) */ set_memory_value_at ( 100, 1 ); /* 100 番地のセルに 1 を記録する */ set_memory_value_at ( 101, 10 ); /* 101 番地のセルに 10 を記録する */ /* * メモリの操作 ( 情報の参照 : get_memory_value_at ) */ printf ( "100 番地のセルに記録されている数値は %d です。\n", get_memory_value_at ( 100 ) ); printf ( "101 番地のセルに記録されている数値は %d です。\n", get_memory_value_at ( 101 ) ); /* * */ return 0; } /* * */
$ ./sample-001.exe 100 番地のセルに記録されている数値は 1 です。 101 番地のセルに記録されている数値は 10 です。 $
Download : sample-002.c
/* * 2020/11/13 sample-002.c */ #include <stdio.h> #include "s_memory.h" /* memory モデルを理解するための関数定義 */ /* * print_memory_value * 指定された address の記憶セルの内容を画面に出力する */ void print_memory_value ( int address ) { printf ( "%d 番地のセルに記録されている数値は %d です。\n", address, get_memory_value_at ( address ) /* 値の取出し */ ); } /* * print_memory_set * メモリへの記憶操作を行い、それを報告する */ void print_memory_set ( int address, int value ) { /* 動作の表示 */ printf ( "%d 番地のセルに %d を記録。\n", address, value ); /* address 番地に value を記録する */ set_memory_value_at ( address, value ); /* 値の設定 */ } /* * print_line * 横棒を表示 */ void print_line ( void ) { printf ( "--------------------------------------\n" ); } /* * */ int main ( void ) { /* * メモリの参照 : 一度記録した情報は何度でも参照できる */ print_memory_set ( 100, 1 ); /* 100 番地のセルに 1 を記録する */ printf ( "一度目 : " ); print_memory_value ( 100 ); /* 100 番地のセルの内容を出力 (一度目) */ printf ( "二度目 : " ); print_memory_value ( 100 ); /* 二度目 */ printf ( "三度目 : " ); print_memory_value ( 100 ); /* 三度目 */ /* * 参照は何度行っても、同じ情報が得られる */ print_line(); /* * 記憶の破壊 : 新しい情報を記録すると以前の記録は失われる */ print_memory_set ( 100, 99 ); /* 100 番地のセルに 99 を記録する */ printf ( "変更後 : " ); print_memory_value ( 100 ); /* 100 番地のセルの内容を出力 */ /* * 新しい情報を記憶すると以前の記録された情報は失われる */ /* * 記録は最後のものだけ ( 参照の有無と無関係に最後のものだけを記録 ) */ print_memory_set ( 100, 21 ); /* 100 番地のセルに 21 を記録する */ print_memory_set ( 100, 22 ); /* 100 番地のセルに 22 を記録する */ print_memory_set ( 100, 23 ); /* 100 番地のセルに 23 を記録する */ printf ( "現在値 : " ); print_memory_value ( 100 ); /* 100 番地のセルの内容を出力 */ /* * 記録されている情報は最後に記録された物だけ */ /* * */ return 0; } /* * */
$ ./sample-002.exe 100 番地のセルに 1 を記録。 一度目 : 100 番地のセルに記録されている数値は 1 です。 二度目 : 100 番地のセルに記録されている数値は 1 です。 三度目 : 100 番地のセルに記録されている数値は 1 です。 -------------------------------------- 100 番地のセルに 99 を記録。 変更後 : 100 番地のセルに記録されている数値は 99 です。 100 番地のセルに 21 を記録。 100 番地のセルに 22 を記録。 100 番地のセルに 23 を記録。 現在値 : 100 番地のセルに記録されている数値は 23 です。 $
Download : sample-003.c
/* * 2020/11/13 sample-003.c */ #include <stdio.h> #include "s_memory.h" /* memory モデルを理解するための関数定義 */ /* * print_memory_value * 指定された address の記憶セルの内容を画面に出力する */ void print_memory_value ( int address ) { printf ( "%d 番地のセルに記録されている数値は %d です。\n", address, get_memory_value_at ( address ) /* 値の取出し */ ); } /* * print_memory_set * メモリへの記憶操作を行い、それを報告する */ void print_memory_set ( int address, int value ) { /* 動作の表示 */ printf ( "%d 番地のセルに %d を記録。\n", address, value ); /* address 番地に value を記録する */ set_memory_value_at ( address, value ); /* 値の設定 */ } /* * print_line * 横棒を表示 */ void print_line ( void ) { printf ( "--------------------------------------\n" ); } /* * */ int main ( void ) { /* * メモリセルの独立性 : 番地の異るセルは独立に振る舞う */ print_memory_set ( 100, 1 ); /* 100 番地のセルに 1 を記録する */ print_memory_set ( 101, 2 ); /* 101 番地のセルに 2 を記録する */ print_memory_value ( 100 ); /* 100 番地のセルの内容を出力 */ print_memory_value ( 101 ); /* 101 番地のセルの内容を出力 */ /* * 番地が異れば、記録されている情報も異る */ /* * 記憶の独立性 */ print_memory_set ( 100, 99 ); /* 100 番地のセルに 99 を記録する */ print_memory_value ( 100 ); /* 100 番地のセルの内容を出力 */ print_memory_value ( 101 ); /* 101 番地のセルの内容を出力 */ print_line(); /* * 100 番地の情報を書き換えても、101 番地の情報は影響しない */ print_memory_set ( 101, 88 ); /* 101 番地のセルに 88 を記録する */ print_memory_value ( 100 ); /* 100 番地のセルの内容を出力 */ print_memory_value ( 101 ); /* 101 番地のセルの内容を出力 */ /* * 逆も真なり */ /* * */ return 0; } /* * */
$ ./sample-003.exe 100 番地のセルに 1 を記録。 101 番地のセルに 2 を記録。 100 番地のセルに記録されている数値は 1 です。 101 番地のセルに記録されている数値は 2 です。 100 番地のセルに 99 を記録。 100 番地のセルに記録されている数値は 99 です。 101 番地のセルに記録されている数値は 2 です。 -------------------------------------- 101 番地のセルに 88 を記録。 100 番地のセルに記録されている数値は 99 です。 101 番地のセルに記録されている数値は 88 です。 $
Download : sample-004.c
/* * 2020/11/13 sample-004.c */ #include <stdio.h> #include "s_memory.h" /* memory モデルを理解するための関数定義 */ /* * print_memory_value * 指定された address の記憶セルの内容を画面に出力する */ void print_memory_value ( int address ) { printf ( "%d 番地のセルに記録されている数値は %d です。\n", address, get_memory_value_at ( address ) /* 値の取出し */ ); } /* * print_memory_set * メモリへの記憶操作を行い、それを報告する */ void print_memory_set ( int address, int value ) { /* 動作の表示 */ printf ( "%d 番地のセルに %d を記録。\n", address, value ); /* address 番地に value を記録する */ set_memory_value_at ( address, value ); /* 値の設定 */ } /* * print_line * 横棒を表示 */ void print_line ( void ) { printf ( "--------------------------------------\n" ); } /* * */ int main ( void ) { /* * メモリセルの容量 */ print_memory_set ( 100, 0 ); /* 100 番地のセルに 0 を記録する */ print_memory_value ( 100 ); /* 100 番地のセルの内容を出力 */ print_memory_set ( 100, 100 ); /* 100 番地のセルに 100 を記録する */ print_memory_value ( 100 ); /* 100 番地のセルの内容を出力 */ print_memory_set ( 100, 255 ); /* 100 番地のセルに 255 を記録する */ print_memory_value ( 100 ); /* 100 番地のセルの内容を出力 */ /* * 0 〜 255 ならば、記録できる */ print_line(); /* * メモリセルの容量オーバー */ print_memory_set ( 100, 300 ); /* 100 番地のセルに 300 を記録しようとした */ print_memory_value ( 100 ); /* 100 番地のセルの内容を出力 */ /* * 300 は記憶されていない !! * 実は 300 を 256 で割った余り ( 44 ) が記録されている * 256 を越える(オーバーする)情報は捨てられる !! */ /* * */ return 0; } /* * */
$ ./sample-004.exe 100 番地のセルに 0 を記録。 100 番地のセルに記録されている数値は 0 です。 100 番地のセルに 100 を記録。 100 番地のセルに記録されている数値は 100 です。 100 番地のセルに 255 を記録。 100 番地のセルに記録されている数値は 255 です。 -------------------------------------- 100 番地のセルに 300 を記録。 100 番地のセルに記録されている数値は 44 です。 $
Download : sample-005.c
/* * 2020/11/13 sample-005.c */ #include <stdio.h> #include "s_variable.h" /* memory モデルを理解するための関数定義 */ /* * */ int main ( void ) { /* * C 言語の変数のメモリモデルによる理解 */ char cvar; /* char 型の変数 cvar の宣言 */ char dvar; /* char 型の変数 dvar の宣言 */ /* * 変数はアドレスをもっている */ printf ( "変数 cvar のアドレスは 16 進数表現で %x です。\n", get_variable_address( cvar ) ); printf ( "変数 dvar のアドレスは 16 進数表現で %x です。\n", get_variable_address( dvar ) ); /* * 変数名が異れば、番地も異っている */ /* * 変数をアドレスを利用して参照 */ cvar = 'c'; /* 変数 cvar に、値 'c' を代入 */ dvar = 'D'; /* 変数 Dvar に、値 'D' を代入 */ printf ( "変数 cvar に記録されている文字は %c です。\n", get_variable_value_at ( get_variable_address( cvar ) ) ); printf ( "変数 dvar に記録されている文字は %c です。\n", get_variable_value_at ( get_variable_address( dvar ) ) ); /* * 変数の値をアドレスを利用して変更 */ set_variable_value_at ( get_variable_address( cvar ), 'X' ); /* 変数 cvar の所に 'X' を記録 */ printf ( "cvar は %c です。\n", cvar ); set_variable_value_at ( get_variable_address( dvar ), 'y' ); /* 変数 dvar の所に 'y' を記録 */ printf ( "dvar は %c です。\n", dvar ); /* * */ return 0; } /* * */
10
$ ./sample-005.exe < sample-005.in 変数 cvar のアドレスは 16 進数表現で 431020fe です。 変数 dvar のアドレスは 16 進数表現で 431020ff です。 変数 cvar に記録されている文字は c です。 変数 dvar に記録されている文字は D です。 cvar は X です。 dvar は y です。 $
Download : sample-006.c
/* * 2020/11/13 sample-006.c */ #include <stdio.h> #include "s_variable.h" /* memory モデルを理解するための関数定義 */ /* * */ int main ( void ) { /* * C 言語の文字列のメモリモデルによる理解 */ /* * 文字列はアドレスをもっている */ printf ( "文字列 \"abc\" のアドレスは 16 進数表現で %x です。\n", get_string_address( "abc" ) ); /* * 文字列の要素をアドレスを利用して参照 */ printf ( "文字列 \"abc\" の先頭の文字は %c です。\n", get_variable_value_at ( get_string_address( "abc" ) ) ); /* * 文字列の要素の二つ目以後を取り出す */ printf ( "文字列 \"abc\" の先頭の次の文字は %c です。\n", get_variable_value_at ( get_string_address( "abc" ) + 1 ) ); printf ( "文字列 \"abc\" の先頭の次の次の文字は %c です。\n", get_variable_value_at ( get_string_address( "abc" ) + 2 ) ); /* * */ return 0; } /* * */
$ ./sample-006.exe 文字列 "abc" のアドレスは 16 進数表現で 401470 です。 文字列 "abc" の先頭の文字は a です。 文字列 "abc" の先頭の次の文字は b です。 文字列 "abc" の先頭の次の次の文字は c です。 $
Download : sample-007.c
/* * 2020/11/13 sample-007.c */ #include <stdio.h> #include "s_variable.h" /* memory モデルを理解するための関数定義 */ /* * */ int main ( void ) { /* * C 言語の変数のメモリモデルによる理解 */ char cvar; /* char 型の変数 cvar の宣言 */ char dvar; /* char 型の変数 dvar の宣言 */ char evar; /* char 型の変数 evar の宣言 */ /* * 変数を並べてて宣言すると (偶然..) アドレスが連続していた.. */ printf ( "変数 cvar のアドレスは 16 進数表現で %x です。\n", get_variable_address( cvar ) ); printf ( "変数 dvar のアドレスは 16 進数表現で %x です。\n", get_variable_address( dvar ) ); printf ( "変数 evar のアドレスは 16 進数表現で %x です。\n", get_variable_address( evar ) ); /* * 変数をアドレスを利用して参照 */ cvar = 'c'; /* 変数 cvar に、値 'c' を代入 */ dvar = 'D'; /* 変数 dvar に、値 'D' を代入 */ evar = '\0'; /* 変数 evar に、値 '\0' を代入 */ printf ( "cvar の所から記録されている文字列は (%s) です。\n", get_variable_address( cvar ) ); /* * アドレス経由で、変数の内容を変更 */ set_variable_value_at ( get_variable_address( cvar ) + 1, 'x' ); /* 変数 cvar のアドレスの次のアドレスは dvar のアドレスなので.. */ printf ( "cvar に記録されている文字は %c です。\n", cvar ); /* 結果的に、dvar の内容が書き変わる */ printf ( "dvar に記録されている文字は %c です。\n", dvar ); /* * */ return 0; } /* * */
$ ./sample-007.exe 変数 cvar のアドレスは 16 進数表現で f17abdad です。 変数 dvar のアドレスは 16 進数表現で f17abdae です。 変数 evar のアドレスは 16 進数表現で f17abdaf です。 cvar の所から記録されている文字列は (cD) です。 cvar に記録されている文字は c です。 dvar に記録されている文字は x です。 $
Download : sample-008.c
/* * 2020/11/13 sample-008.c */ #include <stdio.h> #include "s_variable.h" /* memory モデルを理解するための関数定義 */ /* * */ int main ( void ) { /* * C 言語の変数のメモリモデルによる理解 */ char carray[3]; /* char 型の一次元配列 carray の宣言 (サイズは 3) */ /* 意味的には char carry[0]; -- cvar char carry[1]; -- dvar char carry[2]; -- evar のように考えて良い (cf. sample-007.c) */ /* * 配列の要素のアドレスは連続している事が保証される */ printf ( "変数 carray[0] のアドレスは 16 進数表現で %x です。\n", get_variable_address( carray[0] ) ); printf ( "変数 carray[1] のアドレスは 16 進数表現で %x です。\n", get_variable_address( carray[1] ) ); printf ( "変数 carray[2] のアドレスは 16 進数表現で %x です。\n", get_variable_address( carray[2] ) ); /* * 変数をアドレスを利用して参照 */ carray[0] = 'c'; /* 変数 carray[0] に、値 'c' を代入 */ carray[1] = 'D'; /* 変数 carray[1] に、値 'D' を代入 */ carray[2] = '\0'; /* 変数 carray[2] に、値 '\0' を代入 */ printf ( "carray[0] の所から記録されている文字列は (%s) です。\n", get_variable_address( carray[0] ) ); /* * アドレス経由で、変数の内容を変更 */ set_variable_value_at ( get_variable_address( carray[0] ) + 1, 'x' ); /* 変数 carray[0] のアドレスの次のアドレスは carray[1] のアドレスなので.. */ printf ( "carray[0] に記録されている文字は %c です。\n", carray[0] ); /* 結果的に、carray[1] の内容が書き変わる */ printf ( "carray[1] に記録されている文字は %c です。\n", carray[1] ); /* * */ return 0; } /* * */
$ ./sample-008.exe 変数 carray[0] のアドレスは 16 進数表現で dc674f90 です。 変数 carray[1] のアドレスは 16 進数表現で dc674f91 です。 変数 carray[2] のアドレスは 16 進数表現で dc674f92 です。 carray[0] の所から記録されている文字列は (cD) です。 carray[0] に記録されている文字は c です。 carray[1] に記録されている文字は x です。 $
Download : sample-009.c
/* * 2020/11/13 sample-009.c */ #include <stdio.h> #include "s_variable.h" /* memory モデルを理解するための関数定義 */ /* * */ int main ( void ) { /* * */ char carray[3]; /* char 型の一次元配列 carray の宣言 (サイズは 3) */ /* * 配列の要素のアドレスは連続している事が保証される */ carray[0] = 'c'; /* 変数 carray[0] に、値 'c' を代入 */ carray[1] = 'D'; /* 変数 carray[1] に、値 'D' を代入 */ carray[2] = '\0'; /* 変数 carray[2] に、値 '\0' を代入 */ printf ( "carray[0] の所から記録されている文字列は (%s) です。\n", get_variable_address( carray[0] ) ); /* * 配列名は、文字列と同じように扱える */ printf ( "carray が表現している文字列は (%s) です。\n", carray ); /* * 文字列の一部を変更する事ができる */ carray[1] = 'U'; /* ニ文字目を 'U' に変更 */ printf ( "carray が表現している文字列は (%s) です。\n", carray ); carray[0] = 'p'; /* 一字目を 'p' に変更 */ printf ( "carray が表現している文字列は (%s) です。\n", carray ); /* * */ return 0; } /* * */
$ ./sample-009.exe carray[0] の所から記録されている文字列は (cD) です。 carray が表現している文字列は (cD) です。 carray が表現している文字列は (cU) です。 carray が表現している文字列は (pU) です。 $
Download : sample-010.c
/* * 2020/11/13 sample-010.c */ #include <stdio.h> /* * */ int main ( void ) { /* * 文字配列の初期化 */ char carray[3] = "AB"; /* carray[0] = 'A'; carray[1] = 'B'; carray[2] = '\0'; */ printf ( "carray[0] は %c です。\n", carray[0] ); printf ( "carray[1] は %c です。\n", carray[1] ); /* * */ return 0; } /* * */
$ ./sample-010.exe carray[0] は A です。 carray[1] は B です。 $
Download : sample-011.c
/* * 2020/11/13 sample-011.c */ #include <stdio.h> /* * */ int main ( void ) { /* * アドレス演算子「&」と間接演算子「*」 */ char carray[3] = "AB"; /* * 添字による参照 */ printf ( "carry[0] = %c\n", carry[0] ); printf ( "carry[1] = %c\n", carry[1] ); /* * 間接演算子による参照 */ printf ( "*carry = %c\n", *carry ); printf ( "*(carry+1) = %c\n", *(carry+1) ); /* * address の比較 */ s_print_string ( "&carry[0] = %x\n", &carry[0] ); s_print_string ( "carry = %x\n", carry ); /* * 「&」と「*」は逆演算子 */ s_print_string ( "carry = %x\n", carry ); s_print_string ( "&*carry = %x\n", &*carry ); s_print_string ( "carry[0] = %c\n", carry[0] ); s_print_string ( "*&carry[0] = %c\n", *&carry[0] ); /* * */ return 0; } /* * */
$ ./sample-011.exe carray[0] は A です。 carray[1] は B です。 $
Download : sample-012.c
/* * 2020/11/13 sample-012.c */ #include <stdio.h> #include "s_memory.h" /* memory モデルを理解するための関数定義 */ /* * ◯×ゲームのボード (一次元版) * * y * 0 1 2 (y,t) * +-----+-----+-----+ +-----+ * 0 |(0,0)|(0,1)|(0,2)| |(0,0)| 0 = 0*3+0 = t*3+y * +-----+-----+-----+ +-----+ * t 1 |(1,0)|(1,1)|(1,2)| |(0,1)| 1 = 0*3+1 = t*3+y * +-----+-----+-----+ +-----+ * 2 |(2,0)|(2,1)|(2,2)| |(0,2)| 2 = 0*3+2 = t*3+y * +-----+-----+-----+ +-----+ * |(1,0)| 3 = 1*3+0 = t*3+y * +-----+ * |(1,1)| 4 = 1*3+1 = t*3+y * +-----+ * |(1,2)| 5 = 1*3+2 = t*3+y * +-----+ * |(2,0)| 6 = 2*3+0 = t*3+y * +-----+ * |(2,1)| 7 = 2*3+1 = t*3+y * +-----+ * |(2,2)| 8 = 2*3+2 = x*3+y * +-----+ * */ #define BOARD_SIZE 3 /* ボードのサイズ */ #define SENTE_MARK 'o' /* 先手は 'o' (マル) */ #define GOTE_MARK 'x' /* 後手は 'x' (バツ) */ int main ( void ) { /* * */ char board[BOARD_SIZE*BOARD_SIZE]; /* サイズは 3 × 3 */ int t; /* 縱 */ int y; /* 横 */ /* * ある局面 * * oxx * xoo * oox */ board[0*BOARD_SIZE+0] = 'o'; /* (0,0) */ board[0*BOARD_SIZE+1] = 'x'; /* (0,1) */ board[0*BOARD_SIZE+2] = 'x'; /* (0,2) */ board[1*BOARD_SIZE+0] = 'x'; /* (1,0) */ board[1*BOARD_SIZE+1] = 'o'; /* (1,1) */ board[1*BOARD_SIZE+2] = 'o'; /* (1,2) */ board[2*BOARD_SIZE+0] = 'o'; /* (2,0) */ board[2*BOARD_SIZE+1] = 'x'; /* (2,1) */ board[2*BOARD_SIZE+2] = 'x'; /* (2,2) */ /* * */ t = 0; while ( t < BOARD_SIZE ) { y = 0; while ( y < BOARD_SIZE ) { printf ( "%c", board[t*BOARD_SIZE+y] ); y = y + 1; } printf ( "\n" ); t = t + 1; } /* * */ return 0; } /* * */
$ ./sample-012.exe oxx xoo oxx $
Download : sample-013.c
/* * 2020/11/13 sample-013.c */ #include <stdio.h> /* * ◯×ゲームのボード (一次元版) * * y * 0 1 2 (y,t) * +-----+-----+-----+ +-----+ * 0 |(0,0)|(0,1)|(0,2)| |(0,0)| 0 = 0*3+0 = t*3+y * +-----+-----+-----+ +-----+ * t 1 |(1,0)|(1,1)|(1,2)| |(0,1)| 1 = 0*3+1 = t*3+y * +-----+-----+-----+ +-----+ * 2 |(2,0)|(2,1)|(2,2)| |(0,2)| 2 = 0*3+2 = t*3+y * +-----+-----+-----+ +-----+ * |(1,0)| 3 = 1*3+0 = t*3+y * +-----+ * |(1,1)| 4 = 1*3+1 = t*3+y * +-----+ * |(1,2)| 5 = 1*3+2 = t*3+y * +-----+ * |(2,0)| 6 = 2*3+0 = t*3+y * +-----+ * |(2,1)| 7 = 2*3+1 = t*3+y * +-----+ * |(2,2)| 8 = 2*3+2 = x*3+y * +-----+ * */ #define BOARD_SIZE 3 /* ボードのサイズ */ #define SENTE_MARK 'o' /* 先手は 'o' (マル) */ #define GOTE_MARK 'x' /* 後手は 'x' (バツ) */ /* * 二次元の座標を一次元に変換する関数 */ int index2d ( int t, int y ) { return t * BOARD_SIZE + y; } int main ( void ) { /* * */ char board[BOARD_SIZE*BOARD_SIZE]; /* サイズは 3 × 3 */ int t; /* 縱 */ int y; /* 横 */ /* * ある局面 * * oxx * xoo * oox */ board[index2d(0,0)] = 'o'; /* (0,0) */ board[index2d(0,1)] = 'x'; /* (0,1) */ board[index2d(0,2)] = 'x'; /* (0,2) */ board[index2d(1,0)] = 'x'; /* (1,0) */ board[index2d(1,1)] = 'o'; /* (1,1) */ board[index2d(1,2)] = 'o'; /* (1,2) */ board[index2d(2,0)] = 'o'; /* (2,0) */ board[index2d(2,1)] = 'x'; /* (2,1) */ board[index2d(2,2)] = 'x'; /* (2,2) */ /* * */ t = 0; while ( t < BOARD_SIZE ) { y = 0; while ( y < BOARD_SIZE ) { printf ( "%c", board[index2d(t,y)] ); y = y + 1; } printf ( "\n" ); t = t + 1; } /* * */ return 0; } /* * */
$ ./sample-013.exe oxx xoo oxx $
Download : sample-014.c
/* * 2020/11/13 sample-014.c */ #include <stdio.h> /* * ◯×ゲームのボード (二次元版) * * y * 0 1 2 * +-----+-----+-----+ * 0 |(0,0)|(0,1)|(0,2)| * +-----+-----+-----+ * t 1 |(1,0)|(1,1)|(1,2)| * +-----+-----+-----+ * 2 |(2,0)|(2,1)|(2,2)| * +-----+-----+-----+ * */ #define BOARD_SIZE 3 /* ボードのサイズ */ #define SENTE_MARK 'o' /* 先手は 'o' (マル) */ #define GOTE_MARK 'x' /* 後手は 'x' (バツ) */ int main ( void ) { /* * */ char board[BOARD_SIZE][BOARD_SIZE]; /* サイズは 3 × 3 */ int t; /* 縱 */ int y; /* 横 */ /* * ある局面 * * oxx * xoo * oox */ board[0][0] = 'o'; /* (0,0) */ board[0][1] = 'x'; /* (0,1) */ board[0][2] = 'x'; /* (0,2) */ board[1][0] = 'x'; /* (1,0) */ board[1][1] = 'o'; /* (1,1) */ board[1][2] = 'o'; /* (1,2) */ board[2][0] = 'o'; /* (2,0) */ board[2][1] = 'x'; /* (2,1) */ board[2][2] = 'x'; /* (2,2) */ /* * */ t = 0; while ( t < BOARD_SIZE ) { y = 0; while ( y < BOARD_SIZE ) { printf ( "%c", board[t][y] ); y = y + 1; } printf ( "\n" ); t = t + 1; } /* * */ return 0; } /* * */
$ ./sample-014.exe oxx xoo oxx $
Download : sample-015.c
/* * 2020/11/13 sample-015.c */ #include <stdio.h> /* * ◯×ゲームのボード (一次元版) * * y * 0 1 2 (y,t) * +-----+-----+-----+ +-----+ * 0 |(0,0)|(0,1)|(0,2)| |(0,0)| 0 = 0*3+0 = t*3+y * +-----+-----+-----+ +-----+ * t 1 |(1,0)|(1,1)|(1,2)| |(0,1)| 1 = 0*3+1 = t*3+y * +-----+-----+-----+ +-----+ * 2 |(2,0)|(2,1)|(2,2)| |(0,2)| 2 = 0*3+2 = t*3+y * +-----+-----+-----+ +-----+ * |(1,0)| 3 = 1*3+0 = t*3+y * +-----+ * |(1,1)| 4 = 1*3+1 = t*3+y * +-----+ * |(1,2)| 5 = 1*3+2 = t*3+y * +-----+ * |(2,0)| 6 = 2*3+0 = t*3+y * +-----+ * |(2,1)| 7 = 2*3+1 = t*3+y * +-----+ * |(2,2)| 8 = 2*3+2 = x*3+y * +-----+ * */ #define BOARD_SIZE 3 /* ボードのサイズ */ #define SENTE_MARK 'o' /* 先手は 'o' (マル) */ #define GOTE_MARK 'x' /* 後手は 'x' (バツ) */ int main ( void ) { /* * */ char board[BOARD_SIZE][BOARD_SIZE]; /* サイズは 3 × 3 */ int t; /* 縱 */ int y; /* 横 */ /* * */ printf ( "sizeof ( board[0][0] ) = %d\n", sizeof ( board[0][0] ) ); printf ( "sizeof ( board[0] ) = %d\n", sizeof ( board[0] ) ); printf ( "\n" ); for ( t = 0; t < BOARD_SIZE; t++ ) { printf ( "board[%d]=%x\n", t, &board[t] ); for ( y = 0; y < BOARD_SIZE; y++ ) { /* アドレスの表示 */ printf ( "\t(%d,%d)=%x\n", t, y, &board[t][y] ); } printf ( "\n" ); } /* * */ return 0; } /* * */
$ ./sample-015.exe sizeof ( board[0][0] ) = 1 sizeof ( board[0] ) = 3 board[0]=70eebb0 (0,0)=70eebb0 (0,1)=70eebb1 (0,2)=70eebb2 board[1]=70eebb3 (1,0)=70eebb3 (1,1)=70eebb4 (1,2)=70eebb5 board[2]=70eebb6 (2,0)=70eebb6 (2,1)=70eebb7 (2,2)=70eebb8 $
Download : sample-017.c
/* * 2020/11/13 sample-017.c */ #include <stdio.h> /* * 再帰を利用した階乗の計算(既出) * * 1 ( n < 1 ) * n! = { * n * { (n-1)! } */ int fact ( int n ) { if ( n < 1 ) { // n が 0 の時 return 1; } else { return fact ( n - 1 ) * n; // 再帰を利用して計算 } } int main ( void ) { /* * */ int n = 5; /* * */ printf ( "fact(%d)=%d\n", n, fact(n) ); /* * */ return 0; } /* * */
$ ./sample-017.exe fact(5)=120 $
Download : sample-018.c
/* * 2020/11/13 sample-018.c */ #include <stdio.h> /* * 仮引数変数 n のアドレスと値はどうなっているか ? */ int fact ( int n ) { int f; printf ( "(fact:前) n = %d, &n = %x\n", n, &n ); if ( n < 1 ) { f = 1; } else { f = fact ( n - 1 ) * n; } printf ( "(fact:後) n = %d, &n = %x\n", n, &n ); return f; } int main ( void ) { /* * */ int n = 5; int f; /* * */ printf ( "(main) n = %d, &n = %x\n", n, &n ); /* * */ f = fact(n); printf ( "fact(%d)=%d\n", n, f ); /* * */ return 0; } /* * */
$ ./sample-018.exe (main) n = 5, &n = 38ab48 (fact:前) n = 5, &n = 38ab1c (fact:前) n = 4, &n = 38aaec (fact:前) n = 3, &n = 38aabc (fact:前) n = 2, &n = 38aa8c (fact:前) n = 1, &n = 38aa5c (fact:前) n = 0, &n = 38aa2c (fact:後) n = 0, &n = 38aa2c (fact:後) n = 1, &n = 38aa5c (fact:後) n = 2, &n = 38aa8c (fact:後) n = 3, &n = 38aabc (fact:後) n = 4, &n = 38aaec (fact:後) n = 5, &n = 38ab1c fact(5)=120 $
Download : sample-019.c
/* * 2020/11/13 sample-019.c */ #include <stdio.h> /* * 引数のアドレスは ? ( 引数の順に並んいる ) */ int subfunc ( int a, int b ) { printf ( "a = %d, &a = %x\n", a, &a ); printf ( "b = %d, &b = %x\n", b, &b ); } int main ( void ) { /* * */ subfunc ( 2, 4 ); /* * */ return 0; } /* * */
$ ./sample-019.exe a = 2, &a = ce12f6bc b = 4, &b = ce12f6b8 $
Download : sample-020.c
/* * 2020/11/13 sample-020.c */ #include <stdio.h> /* * 一つの引数変数から(ポインター経由で..)他の引数変数を参照する事ができる */ int subfunc ( int a, int b ) { printf ( "a = %d, &a = %x\n", a, &a ); printf ( "b = %d, &b = %x\n", b, &b ); /* * 変数 b を利用して変数 a の値が参照できる */ printf ( "*(&b-1) = %d, &b-1 = %x\n", *(&b-1), &b-1 ); /* * 変数 b を利用して変数 a の値を変更(代入)できる */ *(&b-1) = 10; printf ( "a = %d\n", a ); } int main ( void ) { /* * */ subfunc ( 2, 4 ); /* * */ return 0; } /* * */
$ ./sample-020.exe a = 2, &a = acf5b0ec b = 4, &b = acf5b0e8 *(&b-1) = 0, &b-1 = acf5b0e4 a = 2 $
Download : sample-021.c
/* * 2020/11/13 sample-021.c */ #include <stdio.h> /* * 先頭の引数のポインタを利用して、残りの引数を参照する */ int subfunc ( int a, ... ) { printf ( "a = %d, &a = %x\n", a, &a ); printf ( "*(&a+1) = %d, &a + 1 = %x\n", *(&a+1), &a+1 ); printf ( "*(&a+2) = %d, &a + 2 = %x\n", *(&a+2), &a+2 ); } int main ( void ) { /* * */ subfunc ( 1,2,3,4,5 ); /* * */ return 0; } /* * */
$ ./sample-021.exe a = 1, &a = cdd91ccc *(&a+1) = -1569530976, &a + 1 = cdd91cd0 *(&a+2) = 11095, &a + 2 = cdd91cd4 $
Download : sample-022.c
/* * 2020/11/13 sample-022.c */ #include <stdio.h> /* * 引数をアドレス経由で参照する * 最初の引数 n は、他の引数の個数としての情報を担う * 関数(のプログラム作成時)側では、 * (実行時の呼出の時に)幾つの引数が指定されるかを知る術がない * 最初の引数 n の「値」を信じて振る舞うしかない */ int subfunc ( int n, ... ) { int i; for ( i = 0; i < n; i++ ) { printf ( "arg[%d]=%d\n", i, *(&n+1+i) ); } } int main ( void ) { /* * */ printf ( "subfunc ( 5,1,2,3,4,5 );\n" ); subfunc ( 5,1,2,3,4,5 ); // 1 から 5 の追加の引数の個数を適切に指定 printf ( "subfunc ( 3,9,8,7,6 );\n" ); subfunc ( 3,9,8,7,6 ); // 4 つの追加の引数があるのに 3 としているので、最後の値は利用されない /* * */ return 0; } /* * */
$ ./sample-022.exe subfunc ( 5,1,2,3,4,5 ); arg[0]=0 arg[1]=0 arg[2]=0 arg[3]=3 arg[4]=1121412096 subfunc ( 3,9,8,7,6 ); arg[0]=0 arg[1]=0 arg[2]=0 $
Download : sample-023.c
/* * 2020/11/13 sample-023.c */ #include <stdio.h> #include "s_print.h" /* * 最初の引数に指定した文字列の中に 「%」があったら、後の引数の値に置き換える */ int print_int_with_format ( char *fmt, int a, ... ) { int i; int j; j = 0; i = 0; while ( fmt[i] != '\0' ) { /* 文字列の終わりがくるまで */ if ( fmt[i] == '%' ) { /* '%' がきたら特別処理 printf ( "%d", *(&a+j) ); /* 追加引数の値を取り出し出力 */ j = j + 1; /* 次の引数の準備 */ } else { /* '%' 以外は.. */ s_print_char ( fmt[i] ); /* その文字をそのまま出力 */ } i = i + 1; /* 次の文字 */ } } int main ( void ) { /* * */ print_int_with_format ( "%\n", 99 ); print_int_with_format ( "i = %, j = %\n", 10, 20 ); print_int_with_format ( "1 st = %, 2nd = %, 3rd = % \n", 10, 20, 90 ); /* * */ return 0; } /* * */
$ ./sample-023.exe i = , j = 1 st = , 2nd = , 3rd = $
Download : sample-024.c
/* * 2020/11/13 sample-024.c */ #include <stdio.h> #include "s_print.h" /* * */ int main ( void ) { /* * */ // printf ( "..." ); /* これまで printf は「文字列出力」専門だった */ /* 実は、もっと、凄い機能がある */ printf ( "%d\n", 99 ); // 文字列の中に「%d」をいれると、これは、その後の引数の // 整数値引数の値に書き変わる /* * 引数の個数は可変長 */ printf ( "i=%d, j=%d, k=%d\n", 10, 20, 90 ); /* * 上と同じ事をする命令列 ( いままでは面倒な事をしていた ) */ s_print_string ( "i=" ); s_print_int ( 10 ); s_print_string ( ", j=" ); s_print_int ( 20 ); s_print_string ( ", k=" ); s_print_int ( 90 ); s_print_newline(); /* * */ return 0; } /* * */
$ ./sample-024.exe 99 i=10, j=20, k=90 i=10, j=20, k=90 $
Download : sample-025.c
/* * 2020/11/13 sample-025.c */ #include <stdio.h> #include "s_print.h" /* * printf を利用してみる */ int main ( void ) { /* * */ printf ( "abc\n" ); /* いままでと同じ */ /* 文字列がそのままでる */ printf ( "i=%d\n", 10 ); /* 文字列の中の 「%d」の部分が、二つ目の引数 10 に変る */ printf ( "i=%d, j=%d\n", 10, 20 ); /* 「%d」が二度でれば二度めは三つ目の引数の値を利用 */ printf ( "a=%f\n", 12.34 ); /* 実数(浮動小数点数) の場合は 「%f」を使う */ printf ( "i=%d, a=%f, c=%c, s=%s\n", 123, 12.34, 'a', "abc" ); /* 混在も可能 %c が文字 %s が文字列(文字型へのポインタ値) */ /* * */ return 0; } /* * */
$ ./sample-025.exe abc i=10 i=10, j=20 a=12.340000 i=123, a=12.340000, c=a, s=abc $
Download : sample-026.c
/* * 2020/11/13 sample-026.c */ #include <stdio.h> #include "s_print.h" /* * printf の更なる機能 : 書式付きの出力 */ int main ( void ) { /* * 同じ数値を異る形式(書式 / format)で出力できる */ printf ( "a=%10.6f\n", -12.34 ); /* 出力する形式を指定できる 10.6 は、全体 10 桁、小数点以下 6 桁の意味 */ printf ( "a=%20.10f\n", -12.34 ); /* 出力する形式を指定できる 20.10 は、全体 20 桁、小数点以下 10 桁の意味 */ /* * */ return 0; } /* * */
$ ./sample-026.exe a=-12.340000 a= -12.3400000000 $
Download : sample-027.c
/* * 2020/11/13 sample-027.c */ #include <stdio.h> #include "s_print.h" /* * scanf, printf (出力関数) の入力版 */ int main ( void ) { /* * */ int i; /* * */ printf ( "i の値を入力してください " ); scanf ( "%d", &i ); /* '%d' --> printf と同じ */ /* i = s_input_int(); */ /* i = 99; の時 scanf ( "%d", i ); は、 scanf ( "%d", 99 ); の意味。 これでは、scanf はどうやっても i の値を得る事ができない。 そこで、「&i」を指定 ( i のポインタ値がわかれば、 i の値が変更できる ) */ /* * */ printf ( "入力された i の値は %d でした\n", i ); /* * */ return 0; } /* * */
10
$ ./sample-027.exe < sample-027.in i の値を入力してください 10 入力された i の値は 10 でした $
/* * 課題 20201113-01 * * 20201113 20201113-01-QQQQ.c * * 浮動小数点数の配列の要素内の数値の総和を求める。 */ #include <stdio.h> /* * 浮動小数点数の配列の要素内の数値の総和を求める。 * * 利用方法 * コンパイル * cc -o BASENAME.exe 20201113-01-QQQQ.c * 実行 * ./BASENAME.exe */ #include <stdio.h> /* * double dsum ( double ary[], int size ) * 浮動小数点数の配列の要素内の数値の総和を求める関数 * double ary[]; 総和を求める要素を含む配列 * int size; 配列のサイズ * * 関数の引数に配列名を指定する * => 関数で、呼び出した側の配列の要素を参照できる */ double dsum ( double ary[], int size ) { /* 仮引数変数 ary が、実引数に指定された配列名(data)と同じようにふるまう */ double sum = 0.0; /* 総和は最初は 0 */ int i; /* 配列の要素を参照する添字変数 */ for ( i = 0; i < size; i++ ) { /* i = 0 〜 sum - 1 の間.. */ sum = sum + ary[i]; /* sum に ary[i] の値を加える */ /* 「sum += ary[i]」とも書きける */ } return sum; /* 結果を返す */ } /* * main * * 全体の流れ * 配列にデータを入力する * データが一遍にプログラムから利用できるようになる * 入力された配列データに対して、処理を行う * <<いままでとの違い>> * 配列がなかったので、たくさんのデータを保持できなかった * => 入力して、即計算をしていた * (入力と、計算を交互に行っていた) * 配列があるので、たくさんのデータを保持する事が可能になる */ #define ARY_SIZE 5 int main( int argc, char *argv[] ) { double data[ARY_SIZE]; /* 大きさ ARY_SIZE の配列の宣言 */ int i; /* 配列の要素を参照する添字変数 */ double sum; /* 総和の計算結果を保持する */ /* とりあえず、データをすべて入力して配列に収める */ printf ( "%d 個のデータを入力します。\n", ARY_SIZE ); for ( i = 0; i < ARY_SIZE; i++ ) { printf ( "%d 番目の数値を入力してください : ", i + 1 ); /* i + 1 番目の数値を、配列要素 data[i] に保存する */ scanf ( "%lf", &data[i] ); } /* 配列に入っているデータをまとめて処理する */ /* 「関数の実引数に『配列名』を指定」 */ sum = dsum ( data, ARY_SIZE ); printf ( "入力されたデータの総和は %f です。\n", sum ); return 0; }
/* * 課題 20201113-02 * * 20201113 20201113-02-QQQQ.c * * 文字列の途中に文字を挿入する * * 利用方法 * コンパイル * cc -o BASENAME.exe 20201113-02-QQQQ.c * 実行 * ./BASENAME.exe */ #include <stdio.h> /* * */ /* * main * */ #define CSIZE 10 #define EOS '\0' int main( int argc, char *argv[] ) { char cary[CSIZE] = { 'a', 'b', 'c', 'd', 'e', EOS }; /* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | cary|'a'|'b'|'c'|'d'|'e'|EOS| ? | ? | ? | ? | */ /* cary[CSIZE] = "abcde" としているように見える */ /* 配列の要素も、宣言時に初期化が可能 */ /* 要素の初期値を {}で挟んで、並べればよい */ /* !! 初期化する値は、配列の要素以下であればよい */ /* !! => 初期値の個数が足りない場合は、あまりは初期化されない */ /* 逆に、初期値を指定すれば、配列サイズを省略できる */ /* その場合は、配列のサイズは、その初期値の個数になる */ int i; int l; /* 文字列の長さを求める */ printf ( "最初の cary = %s\n", cary ); /* 文字列 "abcde" の入った文字配列 cary の 3 文字目 ('c') と 4 文字目 'd' の間に、一文字 'X' を入れる */ /* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 前 cary|'a'|'b'|'c'|'d'|'e'|EOS| ? | ? | ? | ? | \ \ \ 後 cary|'a'|'b'|'c'|'X'|'d'|'e'|EOS| ? | ? | ? | => これを実現するには、後ろから移動する必要 */ /* 文字列の長さを求める */ for ( l = 0; cary[l] != EOS; l++ ) { /* 中身は空っぽ */ } /* for 構文から抜けたときには、 cary[l] == EOS が成立している l が cary の表す文字列の長さになっている */ /* cary の中の文字列の長さは、変数 l に入る */ for ( i = l; 3 <= i; i-- ) { /* 後ろからコピーする必要がある */ cary[i+1] = cary[i]; /* 後ろから、後ろに一つずつコピー */ } cary[3] = 'X'; /* 空けた場所に 'X' を入れる */ /* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | cary|'a'|'b'|'c'|'d'|'e'|EOS| ? | ? | ? | ? | | | | \ \ \ cary|'a'|'b'|'c'|'X'|'d'|'e'|EOS| ? | ? | ? | ? | */ printf ( "'X' を挿入した結果 : %s\n", cary ); return 0; }
/* * 20201113-03-QQQQ.c * 一行分の文字列を入力して、その中の文字列を全て大文字に変換する */ #include <stdio.h> /* * islower (ch) : 指定された文字が、小文字かどうかを判定する */ int islower ( int ch ) { return 'a' <= ch && ch <= 'z'; /* 'a' 〜 'z' なら小文字 */ } /* * toupper ( ch ) : 指定された文字が、小文字なら大文字に変換 */ int toupper ( int ch ) { if ( islower ( ch ) ) { /* 小文字だった.. */ /* 小文字なので、大文字に変換する */ return ch - 'a' + 'A'; /* 小文字から大文字への変換 */ } else { /* そうでないなら */ return ch; /* そのまま返す */ } } /* * main */ #define EOS '\0' /* EOS を定義 */ #define LINE_SIZE 128 /* 入力するのに十分に大きなサイズにする */ int main ( void ) { char line[LINE_SIZE]; int i; printf ( "小文字を含んだ文字列を入力してください : " ); /* 文字列の入力には、fgets を使う */ fgets( line, LINE_SIZE, stdin ); /* 入力に「改行」が含まれる */ for ( i = 0; line[i] != EOS; i++ ) { line[i] = toupper ( line[i] ); /* 小文字を大文字に変換 */ } printf ( "結果 : %s", line ); /* 出力では改行を追加しない */ return 0; }
/* * 20201120-01-QQQQ.c * キーボードから一行の文字列を入力し、その中にある 'a' の個数を出力する */ #include <stdio.h> #define LINE_SIZE 128 /* 入力する文字列の長さ */ #define EOS '\0' /* End Of String (文字列の終り) */ /* * main */ int main ( void ) { char line[LINE_SIZE]; /* 入力する文字列を保存する文字配列 */ /* EOS を含め LINE_SIZE だけ入力する */ int colomun; /* 現在、見ている文字列の中の文字の位置 */ int count = 0; /* 文字列内に含まれる 'a' の個数 */ printf ( "キーボードから一行の文字列を入力してください : " ); /* 標準入力(stdin : キーボード)から一行入力する */ fgets( line, LINE_SIZE, stdin ); for ( colomun = 0; colomun < LINE_SIZE; colomun++ ) { /* 入力された文字列の最初(0)から最後(LINE_SIZE-1)まで.. */ /* 実際は、途中に EOS があるので、途中で抜けてしまう.. */ if ( line[colomun] == EOS ) { /* 途中で、EOS を発見したら.. (文字列の終りなので..) */ break; /* for 構文から抜けてしまう */ } else if ( line[colomun] == 'a' ) { /* 'a' を発見したので.. */ /* 個数を増やす */ count = count + 1; /* count++; でもよい */ } /* else {} */ /* 他の文字の場合は何もしない.. */ } printf ( "入力の中には %d 個の 'a' が含まれていました\n", count ); return 0; }
#include <stdio.h> int main(void) { int a[3]; /* a[0], a[1], a[2] */ int b[3][2]; /* b <-> { b[0], b[1], b[2] } { { b[0][0], b[0][1] }, { b[1][0], b[1][1] }, { b[2][0], b[2][1] } } b[0] b[0][0], b[0][1] b[1] b[1][0], b[1][1] b[2] b[2][0], b[2][1] */ int c[4][3][2]; /* c -> { c[0], c[1], c[2], c[3] } { { c[0][0], c[0][1], c[0][2] }, { c[1][0], c[1][1], c[1][2] }, { c[2][0], c[2][1], c[2][2] }, { c[3][0], c[3][1], c[3][2] } }, { { { { c[0][0][0], c[0][0][1] }, { c[0][1][0], c[0][1][1] }, { c[0][2][0], c[0][2][1] } }, ... } */ /* (一次元)配列の配列を二元配列 二次元配列の配列を三次元配列 .. */ return 0; }
#include <stdio.h> int main(void) { printf ( "Hello, World\n" ); /* 画面に「Hello, World」+改行を表示する */ /* 「"Hello, World\n"」を「文字列」 */ return 0; }
#include <stdio.h> /* 関数 sub は、printf の機能を使って、 printf の「文字列を出力する」という 限定機能 */ void sub ( char *string ) { /* 仮引数変数の宣言には 「char *」 */ printf ( string ); } int main(void) { sub ( "Hello, World\n" ); /* 関数の実引数に文字列を指定できる */ /* 画面に「Hello, World」+改行を表示する */ /* 「"Hello, World\n"」を「文字列」 */ return 0; }
#include <stdio.h> int main(void) { printf ( "%s の先頭の文字は %c です\n", "abc", *"abc" ); printf ( "abc\n" + 1 ); return 0; }
#include <stdio.h> int main(void) { printf ( "*(\"%s\"+0) = %c\n", "abc", *("abc"+0) ); printf ( "*(\"%s\"+1) = %c\n", "abc", *("abc"+1) ); printf ( "*(\"%s\"+2) = %c\n", "abc", *("abc"+2) ); printf ( "*(\"%s\"+3) = %c\n", "abc", *("abc"+3) ); /* EOS ('\0') */ /* "abc" -> 'a', 'b', 'c', '\0' */ return 0; }
#include <stdio.h> int main(void) { printf ( "\"%s\"[0] = %c\n", "abc", "abc"[0] ); printf ( "\"%s\"[1] = %c\n", "abc", "abc"[1] ); printf ( "\"%s\"[2] = %c\n", "abc", "abc"[2] ); printf ( "\"%s\"[3] = %c\n", "abc", "abc"[3] ); /* EOS ('\0') */ /* "abc" -> 'a', 'b', 'c', '\0' */ return 0; }
#include <stdio.h> #define EOS '\0' /* 以下、EOS が出たら '\0' に置き換える */ int main(void) { char cary[10]; cary[0] = 'a'; cary[1] = 'b'; cary[2] = 'c'; /* cary <-> { 'a', 'b', 'c', ??? } */ cary[3] = EOS; /* 文字列の終わりに、EOS をいれる */ /* cary <-> { 'a', 'b', 'c', EOS, ??? } */ /* <-> "abc" */ printf ( "cary = \"%s\"\n", cary ); printf ( "\"abc\" = \"%s\"\n", "abc" ); return 0; }
#include <stdio.h> #define EOS '\0' /* 以下、EOS が出たら '\0' に置き換える */ int main(void) { "abc"[1] = 'B'; /* 文字列 "abc" -> "aBc" に変える */ /* => これは許されない */ return 0; }
#include <stdio.h> #define EOS '\0' /* 文字列を入力する 文字配列に、文字を入力して、収める */ int main(void) { char string[10]; /* EOS と合わせて 9 文字 */ /* n 文字からなる文字列は n+1 サイズが必要 */ int i; for ( i = 0; i < 10 - 1; i++ ) { /* 文字列には EOS が必要 */ string[i] = getchar(); /* 文字を入力して、収める */ if ( string[i] == '\n' ) { /* 改行が入力された */ /* string[i] = EOS; */ break; } } string[i] = EOS; /* break であっても i < 10 - 1 であっても */ /* i - 1 まで、文字が入っているので、 その後に EOS をいれればよい */ printf ( "入力された文字列は\"%s\"です。\n", string ); return 0; }
#include <stdio.h> #define EOS '\0' /* 文字列を入力する 文字配列に、文字を入力して、収める */ int main(void) { char string[10]; /* EOS と合わせて 9 文字 */ /* n 文字からなる文字列は n+1 サイズが必要 */ scanf ( "%s", string ); /* これはやってはいけない */ printf ( "入力された文字列は\"%s\"です。\n", string ); return 0; }
#include <stdio.h> #define EOS '\0' /* 文字列を入力する 文字配列に、文字を入力して、収める */ int main(void) { char string[10]; /* EOS と合わせて 9 文字 */ /* n 文字からなる文字列は n+1 サイズが必要 */ gets ( string ); /* これはやってはいけない */ printf ( "入力された文字列は\"%s\"です。\n", string ); return 0; }
#include <stdio.h> #include <string.h> /* 関数 strlen を使う */ #define EOS '\0' /* 文字列を入力する 文字配列に、文字を入力して、収める */ int main(void) { char string[10]; /* EOS と合わせて 9 文字 */ /* n 文字からなる文字列は n+1 サイズが必要 */ fgets ( string, 10, stdin ); /* これが推奨 */ /* ただし改行まで読み込まれる */ /* 改行が嫌な場合 */ if ( strlen ( string ) > 0 ) { /* 空文字列でない */ if ( string[strlen(string)-1] == '\n' ) { /* 最後の文字が改行 */ string[strlen(string)-1] = EOS; /* 改行を削る */ } } printf ( "入力された文字列は\"%s\"です。\n", string ); return 0; }
#include <stdio.h> #define EOS '\0' /* 文字列を入力する 文字配列に、文字を入力して、収める */ int main(void) { char string[10]; /* EOS と合わせて 9 文字 */ /* n 文字からなる文字列は n+1 サイズが必要 */ scanf ( "%9s", string ); /* 書式指定に、文字列のサイズが指定できる */ printf ( "入力された文字列は\"%s\"です。\n", string ); return 0; }
#include <stdio.h> #define EOS '\0' /* キーボードから、文字入力を繰り返す事により、 文字配列に、文字を入力し、 最後に EOS を追加する事により、 文字配列内に、文字列を格納する */ void mygets ( char line[], int size ) { int i; for ( i = 0; i < size - 1; i++ ) { line[i] = getchar(); if ( line[i] == '\n' ) { break; } } line[i] = EOS; /* i が size - 1 になるか、改行がはいる */ /* いずれにせよ i の所に EOS をいれればよい */ } #define LINE_SIZE 128 int main(void) { char line[LINE_SIZE]; /* 関数の実引数に、配列名を指定する */ mygets ( line, LINE_SIZE ); /* (結果的に..) 配列の要素の値が変更されている */ printf ( "入力は\"%s\"です。\n", line ); return 0; }
#include <stdio.h> void func( int arg ) { printf ( "arg = %d\n", arg ); arg = arg * 2; /* 仮引数変数の値は代入によって変更可能 */ /* 実引数への影響 ?? */ printf ( "arg = %d\n", arg ); } int main(void) { int var = 10; printf ( "var = %d\n", var ); func ( var ); /* 関数の引数に変数を指定しても、関数の影響を受けない */ /* => 関数内で勝手に変数の値を変更されると困る */ /* そもそも、定数を指定する事もある */ /* 指定した定数の値が変更されるのも変.. */ printf ( "var = %d\n", var ); return 0; }
#include <stdio.h> void func( int arg ) { printf ( "arg = %d\n", arg ); arg = arg * 2; /* 仮引数変数の値は代入によって変更可能 */ /* 実引数への影響 ?? */ printf ( "arg = %d\n", arg ); } int main(void) { int var[10]; /* var[0], var[1], .., var[9] */ var[0] = 10; /* 配列の要素は、単純変数と同じ */ printf ( "var[0] = %d\n", var[0] ); func ( var[0] ); /* 配列の要素を指定しているので */ /* 配列の要素の値が実引数になる */ printf ( "var[0] = %d\n", var[0] ); return 0; }
#include <stdio.h> void func( int arg[10] ) { printf ( "arg[0] = %d\n", arg[0] ); arg[0] = arg[0] * 2; /* 仮引数変数を使って、配列の要素を参照 */ /* 実引数で指定した配列の要素への影響 ?? */ printf ( "arg[0] = %d\n", arg[0] ); } int main(void) { int var[10]; /* var[0], var[1], .., var[9] */ var[0] = 10; /* 配列の要素は、単純変数と同じ */ printf ( "var[0] = %d\n", var[0] ); func ( var ); /* 配列名を指定 */ printf ( "var[0] = %d\n", var[0] ); return 0; }
#include <stdio.h> void func( int arg[] ) { /* int arg[10] は非推奨 */ /* => [10] は書いてもよいが、 無視される */ /* => 配列サイズを知るには、 実引数で別に指定する必要がある */ /* 多次元配列の場合は、 この最初のサイズだけを省略する 形式が正しい */ printf ( "arg[0] = %d\n", arg[0] ); arg[0] = arg[0] * 2; /* 仮引数変数を使って、配列の要素を参照 */ /* 実引数で指定した配列の要素への影響 ?? */ printf ( "arg[0] = %d\n", arg[0] ); } int main(void) { int var[10]; /* var[0], var[1], .., var[9] */ var[0] = 10; /* 配列の要素は、単純変数と同じ */ printf ( "var[0] = %d\n", var[0] ); func ( var ); /* 配列名を指定 */ printf ( "var[0] = %d\n", var[0] ); return 0; }
#include <stdio.h> void func( int *arg ) { /* 配列が一次元の場合は、 arg[] の代わりに *arg としてもよいし、 そちらが推奨 */ printf ( "arg[0] = %d\n", arg[0] ); arg[0] = arg[0] * 2; /* 仮引数変数を使って、配列の要素を参照 */ /* 実引数で指定した配列の要素への影響 ?? */ printf ( "arg[0] = %d\n", arg[0] ); } int main(void) { int var[10]; /* var[0], var[1], .., var[9] */ var[0] = 10; /* 配列の要素は、単純変数と同じ */ printf ( "var[0] = %d\n", var[0] ); func ( var ); /* 配列名を指定 */ printf ( "var[0] = %d\n", var[0] ); return 0; }
多次元配列 配列の配列が作れる 普通の変数は 0 次元 k 次元の要素の配列は k+1 次元 配列: すでにあるデータ構造から、それが並んだ新しいデータ構造を作る 構造体: すでにあるデータ構造から、それを組み合わせた新しいデータ構造を作る 配列や構造体を使って作ったデータ構造は、 次のデータ構造を作るための材料になる 多次元配列 配列から配列を作る # 二次元の配列が行列 より一般に 配列から構造体 構造から配列 => いくらでも複雑な組み合わせが可能 新しいデータ構造を作る union ポインター == [復習] 文字列について C 言語では、「文字列」は、 「"(ダブルクォーテーション)」で挟まれた文字列 「文字列」は、関数の実引数に指定する事ができる # 最初の Hello World で、printf に指定している 仮引き数変数の宣言には、(説明無しに..) 「char *」とする !! 「char *」が「文字列」を表す 文字列の操作 文字列から文字の取り出し 文字列の頭に * をつけると、先頭の文字が取り出せる 文字列に +1 すると、 文字列の先頭の文字がなくなり、一文字短く 上記を組み合わせて *(文字列 + n) => 文字列[n] => n 番目(0 から始めて..) !! 文字列は、文字の並びで、最後に EOS('\0') がある *(a+n) <-> a[n] 添え字 文字列 n 番目の文字を取り出す 配列 配列の n 番目の要素を取り出す => もし、「文字列」が「文字配列」であれば、 不思議はない 「文字列」は「文字の並び」だから、「文字配列」 C 言語では、 「文字列」は、「文字の配列」+ EOS からできている C言語のプログラム中に、 "abc" (文字列リテラル) という文字列を書くと、 どこかに、サイズ 4 の文字配列が作られ、 その中身が、'a', 'b', 'c', EOS になっている => 文字配列 => ただし、この「文字列」を表す文字配列は、 その「要素の値を変更」できない => 文字配列と異なる 関数の引数にリテラルを指定する時に注意 文字配列を「文字列」として扱う事もできる 「文字列を入力する」には、 「文字配列」に、「文字」と EOS をいれればよい これを実現するための命令 できるがやってはいけない方法 scanf ( "%s", 配列名 ); gets( 配列名 ); => 配列のサイズを知る事ができない 配列のサイズを超える入力をしてしまう可能性がある => 危険 : buffer over run という典型なミス => セキュリティ上の穴になる # コンピュータウィルス感染の原因 推奨されるのは、fgets を利用する fgets ( 配列名, サイズ, stdin ); => きちんと、サイズを渡しているので、 buffer over run を避ける事ができる !! fgets をつかうと、改行も読み込まれる 関数の引数に、配列名を指定するとどうなるか ? => 関数内で、「配列の要素の値」を「変更」できる <<復習>> 関数の実引数で指定された「値」は、 関数の仮引数変数に代入される 関数の実引数に、配列名を指定し、 関数内で、その配列要素の値を(当然、参照ができるだけでなく) 変更する事ができる => 関数呼び出しによって、関数の呼び出し側の変数の値が 書き変わってしまう可能性がある 得失 失: 関数呼び出しによって、(しらぬまに..) 変数の値が変わる -> わかりにくい 得: 関数によって、配列の要素の変更可能 => 文字列の入力が、関数呼び出しによって、可能になっている !! 「配列名を指定する」 実引数に配列名を指定すると時の、 仮引数変数の宣言の仕方 素直だが、推奨されないのは、 実引数と同じ形の宣言 配列の最初の添え字のサイズを省略するパターン 基本の表現 # 多次元配列の配列名を引数にする場合は、 # この書き方だけが正しい書き方 一次元配列の場合だけは、 [] を仮引数変数の後ろに書く代わりに、 仮引数変数の前に * を付ける流儀が許さるし、 そちらの方が、望ましい。
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20201120-01.c
/* * 20201120-01-QQQQ.c * キーボードから一行の文字列を入力し、その中にある 'a' の個数を出力する */ #include <stdio.h> #define LINE_SIZE 128 /* 入力する文字列の長さ */ #define EOS '\0' /* End Of String (文字列の終り) */ /* * main */ int main ( void ) { char line[LINE_SIZE]; /* 入力する文字列を保存する文字配列 */ /* EOS を含め LINE_SIZE だけ入力する */ int colomun; /* 現在、見ている文字列の中の文字の位置 */ int count = 0; /* 文字列内に含まれる 'a' の個数 */ printf ( "キーボードから一行の文字列を入力してください : " ); /* 標準入力(stdin : キーボード)から一行入力する */ /* ** この部分を完成させなさい */ for ( colomun = 0; colomun < LINE_SIZE; colomun++ ) { /* 入力された文字列の最初(0)から最後(LINE_SIZE-1)まで.. */ /* 実際は、途中に EOS があるので、途中で抜けてしまう.. */ if ( line[colomun] == EOS ) { /* 途中で、EOS を発見したら.. (文字列の終りなので..) */ break; /* for 構文から抜けてしまう */ } else if ( line[colomun] == 'a' ) { /* 'A' を発見したので.. */ /* 個数を増やす */ /* ** この部分を完成させなさい */ } /* else {} */ /* 他の文字の場合は何もしない.. */ } printf ( "入力の中には %d 個の 'a' が含まれていました\n", count ); return 0; }
There are any 'a's included in this line.
$ ./20201120-01-QQQQ.exe キーボードから一行の文字列を入力してください : 入力の中には 3 個の 'a' が含まれていました $