Download : sample-001.c
/*
* 2019/11/22 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
/*
* 2019/11/22 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
/*
* 2019/11/22 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
/*
* 2019/11/22 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
/*
* 2019/11/22 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 進数表現で 4101582e です。 変数 dvar のアドレスは 16 進数表現で 4101582f です。 変数 cvar に記録されている文字は c です。 変数 dvar に記録されている文字は D です。 cvar は X です。 dvar は y です。 $
Download : sample-006.c
/*
* 2019/11/22 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
/*
* 2019/11/22 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 進数表現で 6339bd9d です。 変数 dvar のアドレスは 16 進数表現で 6339bd9e です。 変数 evar のアドレスは 16 進数表現で 6339bd9f です。 cvar の所から記録されている文字列は (cD) です。 cvar に記録されている文字は c です。 dvar に記録されている文字は x です。 $
Download : sample-008.c
/*
* 2019/11/22 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 進数表現で 57affc70 です。 変数 carray[1] のアドレスは 16 進数表現で 57affc71 です。 変数 carray[2] のアドレスは 16 進数表現で 57affc72 です。 carray[0] の所から記録されている文字列は (cD) です。 carray[0] に記録されている文字は c です。 carray[1] に記録されている文字は x です。 $
Download : sample-009.c
/*
* 2019/11/22 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
/*
* 2019/11/22 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
/*
* 2019/11/22 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
/*
* 2019/11/22 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
/*
* 2019/11/22 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
/*
* 2019/11/22 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
/*
* 2019/11/22 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]=1a842c10 (0,0)=1a842c10 (0,1)=1a842c11 (0,2)=1a842c12 board[1]=1a842c13 (1,0)=1a842c13 (1,1)=1a842c14 (1,2)=1a842c15 board[2]=1a842c16 (2,0)=1a842c16 (2,1)=1a842c17 (2,2)=1a842c18 $
Download : sample-017.c
/*
* 2019/11/22 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
/*
* 2019/11/22 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 = 81f1e458 (fact:前) n = 5, &n = 81f1e42c (fact:前) n = 4, &n = 81f1e3fc (fact:前) n = 3, &n = 81f1e3cc (fact:前) n = 2, &n = 81f1e39c (fact:前) n = 1, &n = 81f1e36c (fact:前) n = 0, &n = 81f1e33c (fact:後) n = 0, &n = 81f1e33c (fact:後) n = 1, &n = 81f1e36c (fact:後) n = 2, &n = 81f1e39c (fact:後) n = 3, &n = 81f1e3cc (fact:後) n = 4, &n = 81f1e3fc (fact:後) n = 5, &n = 81f1e42c fact(5)=120 $
Download : sample-019.c
/*
* 2019/11/22 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 = eddf6c6c b = 4, &b = eddf6c68 $
Download : sample-020.c
/*
* 2019/11/22 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 = bb6dcc7c b = 4, &b = bb6dcc78 *(&b-1) = 0, &b-1 = bb6dcc74 a = 2 $
Download : sample-021.c
/*
* 2019/11/22 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 = ab3473ec *(&a+1) = 1291590560, &a + 1 = ab3473f0 *(&a+2) = 11053, &a + 2 = ab3473f4 $
Download : sample-022.c
/*
* 2019/11/22 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]=17130496 subfunc ( 3,9,8,7,6 ); arg[0]=0 arg[1]=0 arg[2]=0 $
Download : sample-023.c
/*
* 2019/11/22 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
/*
* 2019/11/22 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
/*
* 2019/11/22 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
/*
* 2019/11/22 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
/*
* 2019/11/22 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 でした $
/*
* 20181222-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'; /* ASCII Code 表の並びの規則性質から.. */
/*
'b' = 'a' + 1
'B' = 'A' + 1
'b' => 'B'
'a' + 1 => 'A' + 1
'a' + ( 'b' - 'a' ) => 'A' + ( 'b' - 'a' )
'a' + ( 'b' - 'a' ) => 'A' + ( 'B' - 'A' )
'a' + ( ch - 'a' ) => 'A' + ( ch - 'a' )
*/
} else { /* そうでないなら */
return ch; /* そのまま返す */
}
}
/*
* main
*/
#define EOS '\0' /* EOS を定義 */
#define LINE_SIZE 128 /* 入力するのに十分に大きなサイズにする */
int main ( void ) {
char line[LINE_SIZE];
int i;
printf ( "小文字を含んだ文字列を入力してください : " );
fgets ( line, LINE_SIZE, stdin ); /* fgets を利用して、入力 */
for ( i = 0; line[i] != EOS; i++ ) {
line[i] = toupper ( line[i] ); /* 小文字を大文字に変換 */
}
printf ( "結果 : %s", line );
return 0;
}
#include <stdio.h>
void print_variable ( int ivalue ) {
printf ( "value of v = %d\n", ivalue );
/* ivalue には、関数を呼び出す時の実引数で指定された『値』が入っている */
/* その値を参照して、表示する事ができる */
}
int main(int argc, char *argv[]) {
int v;
v = 123;
/* 変数 v の内容を表示する関数を呼び出す事 */
/* => 関数の中から、「変数 v の値を参照する手段」を提供する必要がある */
print_variable ( v ); /* 変数 v の値が、関数に「渡され」れ、
関数中では、仮引数に代入されるので、
その仮引数の値を参照する事により、
(結果的に..) 関数を呼び出す側の変数 v の値
が参照される */
return 0;
}
#include <stdio.h>
void print_array () {
/* 配列の内容を表示する関数 */
}
/*
これで、(配列の要素)10 個の整数値を表示する事ができる
cf.
仮引数変数の宣言
int a[10]
とは、書けない
=> 10 個の値を受け取って、それぞれ、10 個の仮引数変数に代入する
*/
void print_ten (
int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9
) {
printf ( "a[0] = %d\n", a0 );
printf ( "a[1] = %d\n", a1 );
printf ( "a[2] = %d\n", a2 );
printf ( "a[3] = %d\n", a3 );
printf ( "a[4] = %d\n", a4 );
printf ( "a[5] = %d\n", a5 );
printf ( "a[6] = %d\n", a6 );
printf ( "a[7] = %d\n", a7 );
printf ( "a[8] = %d\n", a8 );
printf ( "a[9] = %d\n", a9 );
}
int main(int argc, char *argv[]) {
int a[10];
int i;
for ( i = 0; i < 10; i++ ) {
a[i] = i * i;
}
/* 配列の内容を表示する関数を呼び出す事 */
/* => 関数の中から、「配列の要素を参照する手段」を提供する必要がある */
// print_array ( /* ここで、配列の内容を指定したい.. */ );
/*
print_array ( a[0], a[1], a[2], ..., a[9] );
という方法はある
*/
print_ten ( a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9] );
return 0;
}
#include <stdio.h>
void print_array ( int iarray[10] ) { /* 『配列』が渡された .. ? */
int i;
/* 配列の内容を表示する関数 */
for ( i = 0; i < 10; i++ ) { /* 配列なので、繰り返しを利用して操作できる */
printf ( "a[%d] = %d\n", i, iarray[i] );
}
}
/*
これで、(配列の要素)10 個の整数値を表示する事ができる
cf.
仮引数変数の宣言
int a[10]
とは、書けない
=> 10 個の値を受け取って、それぞれ、10 個の仮引数変数に代入する
*/
void print_ten (
int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9
) {
printf ( "a[0] = %d\n", a0 );
printf ( "a[1] = %d\n", a1 );
printf ( "a[2] = %d\n", a2 );
printf ( "a[3] = %d\n", a3 );
printf ( "a[4] = %d\n", a4 );
printf ( "a[5] = %d\n", a5 );
printf ( "a[6] = %d\n", a6 );
printf ( "a[7] = %d\n", a7 );
printf ( "a[8] = %d\n", a8 );
printf ( "a[9] = %d\n", a9 );
/*
この方法は、確かに動く
「配列」にはそぐわない
関数の中で、「配列」の機能を利用していない
=> 「配列」なら、「繰り返し」が利用できるはずなのに、
それができていない
=> 大きさが「固定」になってしまう
大きさが固定でない「配列」の良さを殺してしまっている
cf.
int b[5] を考えたら、その瞬間に、利用できない
=> データの個数が「 10 である」という情報を「共有」している
=> 結びつきが強くなってしまっている
*/
}
int main(int argc, char *argv[]) {
int a[10]; /* 配列「a」の宣言 => a[0],a[1], .., a[9] という要素 */
int i;
for ( i = 0; i < 10; i++ ) {
a[i] = i * i;
}
/* 配列の内容を表示する関数を呼び出す事 */
/* => 関数の中から、「配列の要素を参照する手段」を提供する必要がある */
/*
print_array ( a[0], a[1], a[2], ..., a[9] );
という方法はある
*/
/* だめパターン
print_ten ( a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9] );
*/
print_array ( /* ここで、配列の内容を指定したい.. */ a /* 配列名を指定 */ );
return 0;
}
#include <stdio.h>
/* 構造体もやってみる */
typedef struct {
int x;
int y;
int z;
} Point3D;
void print_point3D ( Point3D pt ) {
printf ( "( %d, %d, %d )\n", pt.x, pt.y, pt.z );
}
int main(int argc, char *argv[]) {
Point3D p1;
p1.x = 1;
p1.y = 10;
p1.z = 100;
print_point3D ( p1 ); /* 構造体でも、単純変数と同様に引数に指定する */
return 0;
}
#include <stdio.h>
void print_array ( int iarray[10] ) { /* 『配列』が渡された .. ? */
int i;
/* 配列の内容を表示する関数 */
for ( i = 0; i < 10; i++ ) { /* 配列なので、繰り返しを利用して操作できる */
printf ( "a[%d] = %d\n", i, iarray[i] );
}
}
int main(int argc, char *argv[]) {
int a[10];
int b[5];
int c[20];
int i;
for ( i = 0; i < 10; i++ ) {
a[i] = i * i;
}
print_array ( a ); /* 配列 a は、サイズが 10 個 */
for ( i = 0; i < 5; i++ ) {
b[i] = i * i * i;
}
print_array ( b ); /* ?? : 配列 b はサイズが 5 しかないので... */
/* エラーになりそうだが.. */
for ( i = 0; i < 20; i++ ) {
c[i] = - i;
}
print_array ( c ); /* 仮説 その 1 が正しければ、これは NG */
return 0;
}
/*
結果
a[0] = 0
a[1] = 1
a[2] = 4
a[3] = 9
a[4] = 16
a[5] = 25
a[6] = 36
a[7] = 49
a[8] = 64
a[9] = 81 <= ここまでは、適切に動いている
a[0] = 0
a[1] = 1
a[2] = 8
a[3] = 27
a[4] = 64 <= 5 個指定したので、5 個までは、適切に動いている
a[5] = 0
a[6] = 1847592941
a[7] = 32691
a[8] = 0
a[9] = 1 <= 残りの 5 個は何か ?
仮定(その 1):
「配列の要素の『値』が個別にコピーされている」
cf. 単純変数、構造体の場合そうなっている
!! 配列のサイズは固定ではない ( 10 -> 5 )
*/
#include <stdio.h>
void print_array ( int iarray[], int size ) { /* 『配列名』を受け取る */
int i;
/* 配列の内容を表示する関数 */
for ( i = 0; i < size; i++ ) { /* 配列サイズがわからないので、別に与える */
printf ( "a[%d] = %d\n", i, iarray[i] );
}
}
int main(int argc, char *argv[]) {
int a[10];
int i;
for ( i = 0; i < 10; i++ ) {
a[i] = i * i;
}
printf ( "call a, 10\n" );
print_array ( a, 10 ); /* 配列 a は、サイズが 10 個 */
printf ( "call a, 5\n" );
print_array ( a, 5 ); /* 配列 a で、サイズを 5 にする */
/* 要素はどうなっているか ? */
/* a) 10 個コピーされて、5 個しか利用されない */
/* b) 5 個コピーされて、5 個利用する */
/* 「二つ目の引数が、サイズを表している事」は
一般には、わからない
=> b) は考えられない
*/
return 0;
}
#include <stdio.h>
void print_array ( int iarray[], int size ) { /* 『配列名』を受け取る */
int i;
/* 配列の内容を表示する関数 */
for ( i = 0; i < size; i++ ) { /* 配列サイズがわからないので、別に与える */
printf ( "a[%d] = %d\n", i, iarray[i] );
}
/*
もし、「関数の呼び出し側で、コピーする個数が決まる」と仮定すると、
関数側で、その値を受け取る領域のサイズはどうすればよいか ??
*/
}
void print_array_with_message ( char *message, int iarray[], int size ) {
printf ( "Message : %s\n", message );
print_array ( iarray, size );
/*
ここで、
「配列の要素の値をいちいちコピーしている」という仮説は誤り
であることが判明
そもそも、不特定多数のデータのコピーは効率がわるいので、したくない
*/
}
int main(int argc, char *argv[]) {
int a[10];
int c[20];
int i;
for ( i = 0; i < 10; i++ ) {
a[i] = i * i;
}
printf ( "call a, 10\n" );
print_array ( a, 10 ); /* 配列 a は、サイズが 10 個 */
printf ( "call a, 5\n" );
print_array ( a, 5 ); /* 配列 a で、サイズを 5 にする */
/* 要素はどうなっているか ? */
/* a) 10 個コピーされて、5 個しか利用されない */
/* b) 5 個コピーされて、5 個利用する */
/* 「二つ目の引数が、サイズを表している事」は
一般には、わからない
=> b) は考えられない
*/
for ( i = 0; i < 20; i++ ) {
c[i] = - i;
}
print_array_with_message ( "call c, 20", c, 20 );
return 0;
}
#include <stdio.h>
/*
引数に「配列名」を指定する事が、「配列要素」を渡していない
=> どのような原理で「配列名」から、「『配列要素』の参照」を実現するか ?
ヒント:
a[i] <-> *(a+i)
*/
void print_array ( int *iarray, int size ) { /* int iarray[] */
/*
int iarray[i]
<-> int (iarray[i])
<-> int iarray[0]
<-> int *(iarray+0)
<-> int *iarray
*/
int i;
/* iarray は「配列」ではなく、「配列名がもつ値を保持する変数」*/
/* 配列の内容を表示する関数 */
for ( i = 0; i < size; i++ ) {
printf ( "a[%d] = %d\n", i, *(iarray+i) ); /* iarray[i] */
/*
*(iarray+i) 「iarray が持つ値」に i を加えて、* つけたもの
「iarray は仮引数なので、実引数で指定された値をもっている」
=> 「配列名 a」が持つ値
*(a+i)
a[i] 「配列 a の i 番目の要素」を表している
*/
}
}
int main(int argc, char *argv[]) {
int a[10];
int i;
for ( i = 0; i < 10; i++ ) {
*(a+i) = i * i; /* 「a」の値に i を加えて、それに * を付ける
「a[i]」と「同じもの」としてふるまう */
/* 「同じもの」 => 同じ値を持つだけでなく、代入もできる */
/* # 「同じ左辺値を持つ」と表現する */
}
printf ( "call a, 10\n" );
print_array ( a, 10 ); /* 引数に配列名を指定する => 配列名が持つ値がコピーされる */
return 0;
}
/*
「配列名」の値
後ろに、添え字をつけると、要素を表すような値
関数の実引数に配列名を指定した時に渡されるもの
関数の仮引数変数に代入されるもの
=> 配列名を指定するだけで、配列の要素が参照できる
=> 配列の要素のある「場所」を表現する値
*/
#include <stdio.h>
void print_array ( int *iarray, int size ) { /* int iarray[] */
int i;
/* iarray は「配列」ではなく、「配列名がもつ値を保持する変数」*/
/* 配列の内容を表示する関数 */
for ( i = 0; i < size; i++ ) {
printf ( "a[%d] = %d\n", i, *(iarray+i) ); /* iarray[i] */
}
}
/*
配列 の from から form + size - 1 までを出力する
*/
void print_part_array ( int iarray[], int from, int size ) {
int i;
/* 配列の要素の一部分を表示する関数 */
for ( i = from; i < from + size; i++ ) {
printf ( "a[%d] = %d\n", i, *(iarray+i) );
}
}
int main(int argc, char *argv[]) {
int a[10];
int i;
for ( i = 0; i < 10; i++ ) {
*(a+i) = i * i;
}
printf ( "call a, 10\n" );
print_array ( a, 10 );
printf ( "call a, 4, 3\n" );
print_part_array ( a, 4, 3 );
return 0;
}
#include <stdio.h>
void print_array ( int *iarray, int size ) { /* int iarray[] */
int i;
/* iarray は「配列」ではなく、「配列名がもつ値を保持する変数」*/
/* 配列の内容を表示する関数 */
for ( i = 0; i < size; i++ ) {
printf ( "a[%d] = %d\n", i, *(iarray+i) ); /* iarray[i] */
}
}
/*
配列 の from から form + size - 1 までを出力する
*/
void print_part_array ( int iarray[], int from, int size ) {
int i;
/* 配列の要素の一部分を表示する関数 */
/*
for ( i = from; i < from + size; i++ ) {
printf ( "a[%d] = %d\n", i, *(iarray+i) );
}
i = 4, 5, 6 : *(iarray+i)
i = 4, 5, 6 :iarray[i]
iarray[4], iarray[5], iarray[6]
a[4], a[5], a[6]
a[4+0], a[4+1], a[4+2]
*(a+4+0), *(a+4+1), *(a+4+2)
*((a+4)+0), *((a+4)+1), *((a+4)+2)
(a+4)[0], (a+4)[1], (a+4)[2]
「a+4」という配列の先頭の 3 個を出力
*/
print_array ( iarray + from, size );
/* 引数は「式」なので、「場所」の値をもつ「式」が書ける */
/* 「iarray + from」という表現から「iarray」が「配列」を表していない */
}
int main(int argc, char *argv[]) {
int a[10];
int i;
for ( i = 0; i < 10; i++ ) {
*(a+i) = i * i;
}
printf ( "call a, 10\n" );
print_array ( a, 10 );
printf ( "call a, 4, 3\n" );
print_part_array ( a, 4, 3 );
return 0;
}
#include <stdio.h>
void print_array ( int iarray[], int size ) { /* 『配列名』を受け取る */
int i;
/* 配列の内容を表示する関数 */
for ( i = 0; i < size; i++ ) { /* 配列サイズがわからないので、別に与える */
printf ( "a[%d] = %d\n", i, iarray[i] );
}
}
/* 配列の 5 番目の要素の値を、10 倍する */
void modify5 ( int iarray[] ) {
iarray[5] = iarray[5] * 10; /* iarray[5] *= 10 */
}
int main(int argc, char *argv[]) {
int a[10];
int i;
for ( i = 0; i < 10; i++ ) {
a[i] = i * i;
}
printf ( "call a, 10\n" );
print_array ( a, 10 ); /* 配列 a は、サイズが 10 個 */
modify5 ( a ); /* a[5] が 10 倍になる */
printf ( "call a, 10\n" );
print_array ( a, 10 ); /* 配列 a は、サイズが 10 個 */
return 0;
}
#include <stdio.h>
/*
文字列をキーボードから入力する
*/
int main(int argc, char *argv[]) {
char string[1000]; /* 入力されるであろう文字列の長さの文字列が十分に
入るサイズ ( 一行は 80 桁なので、81 でもよさそうだが .. */
scanf ( "%s", string ); /* キーボードから読みこんだ文字列を、
文字配列 string に入れる事ができる */
/*
文字列を入力する書式は 「%s」
入力された文字列を入れる場所は、
「配列」で、その名前を指定(&は不要)
*/
/* 絶対にマネしてはいけない */
/* キーボードから 999 文字までは適切に動く */
/* 999 (入力文字) + EOS = 1000 */
/* それより長い文字列がはいると、配列が溢れてしまう */
/* => バッファーオバーフロー:セキュリティ上の脆弱性になる */
printf ( "Input String is : [%s]\n", string );
return 0;
}
#include <stdio.h>
/*
文字列をキーボードから入力する
gets -> 昔のプログラムにはあったが、今や「危険」なので、削除された
*/
int main(int argc, char *argv[]) {
char string[1000];
gets ( string ); /* 絶対にマネしてはいけない */
/* => いまはできなくなった */
printf ( "Input String is : [%s]\n", string );
return 0;
}
#include <stdio.h>
/*
文字列をキーボードから入力する
fgets
*/
int main(int argc, char *argv[]) {
char string[3];
fgets ( string, 3, stdin ); /* stdin : 今回は説明しない .. */
/* scanf ( "%s", string ) はだめで、fgets が良いか.. */
/* ちゃんと、配列のサイズを指定しているから */
/* fgets は、引数に、配列のサイズを指定する事ができ、
fgets が、そのサイズをみて、サイズ内の文字数だけを入力から、
切り出して、保存してくれる */
printf ( "Input String is : [%s]\n", string );
return 0;
}
前回(2019/11/22)の内容 curses と squash ゲーム curses : キャラクターベースの画面描画ライブラリ squash : curses を利用したキャラクターベースのゲーム => 興味をもつための内容(成績には無関係) 前回のハイライト 配列の情報を、関数に渡すにはどうすればよいか ? 関数の実引数に、「配列名」を指定する事ができる => 関数仮引数で、この「『配列名』を指定する事によって、渡された『値』を利用して」 配列の要素を参照できる cf. 単純変数(『式』)の値を関数に与えるには、実引数に単純変数(式)を指定する => 実引数に、その「単純変数(式)」の「値」が代入される 1. 渡されるは「値」 2. その値は、仮引数に「代入」される => 関数の「仮引数変数」と関数の呼び出し側の関係は、 「値を共有している」 以上のものはない => 関数の呼び出し側と関数の関係が薄くなる # [欠点] 関係が薄いと、効率が悪くなる # [利点] (関係が薄いので..) 他と組み合わせる事が容易になる # C 言語では、関数呼び出しに関しては、 # 「関係を薄くする」事(によって、再利用性を高める事)を重視 !! 仮引数変数の値を変更する(代入)事は、関数の呼び出し側に影響を与えない 配列名を引数に指定できる : 「配列そのもの」が渡されているように見える 「渡す」: 何かしらの「値」が「コピー」される事を「渡す」と呼ぶ => 「配列名」を「渡す」(「配列」は「渡せ」ない ) => 「配列名」が表す(何等かの)「値」が「コピー」される <= 「配列要素」の「値」が「コピー」されるわけではない <= 「配列の要素」は渡されてはいない => どうやって、関数側で「配列の要素の値」を得るか ? # 渡されるのは、配列の最初の要素のポインター値 => 「配列名」は、「配列の要素がある『場所』を示す情報(値)」をもっている 関数の引数に、「場所の情報」を与えれば、その「場所の情報」を利用して、 その場所にある「(配列の)要素」を参照する事ができる # 「配列の要素の値」をコピーせずに、「場所」を渡す理由 # 効率 : 配列のサイズは大きいので、コピーする事は効率がわるい # (良し悪し) : 関数の中で、配列の要素を(直接)変更できる # 良し : 機能が高まる/効率が良い # 悪し : (結果的に配列の要素を共有する事になるので..) 関係が強くなる # => 関数呼び出しによって、「変数の値が変化する」というわかりにくい状況が起きる # 「配列の一部(要素)だけを変更したい」という要望がある # cf. Excel 大量のデータの中の一部だけを更新する 「文字列」の入力は 文字配列の中に、複数の文字と、最後に、'\0' (End Of String) を保存する形になる !! 「文字列」は、「文字配列」で表現できる scanf を利用する場合 形式的には、 scanf ( "%s", 文字配列名 ) で、文字配列に、文字列を入力できるが、この形で、利用するのは『禁止』 上の表現では、scanf に配列のサイズが知らされていないので、危険 実は、 scanf ( "%3s", .. ) のようにサイズを指定する事が可能で、 その場合は安全 さらに、 sannf ( "%*s", サイズ, 文字配列名 ) とする事もできる => 「scanf の書式」でググる !! scanf を利用し場合は、「改行(空白文字)」が入力されない おすすめ fgets ( 配列名, 配列サイズ, stdin ); /* stdin は今回は説明しない */ => これの場合は、「改行」も「入力の一部」になる => 一行ずつ入力する
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20191129-01.c
/*
* DATE-01-QQQQ.c
* メモリ操作での和
* s_memory.h を利用し、
* 100 番地の内容と 101 番地の内容の和を 102 番地に入れるプログラムを作成しなさい
*/
/*
*
*/
#include <stdio.h>
#include "s_memory.h"
/*
* print_memory_value
* 指定された address の記憶セルの内容を画面に出力する
*/
void print_memory_value ( int address ) {
printf ( "%d 番地のセルに記録されている数値は %d です。\n",
address,
get_memory_value_at ( address ) /* 値の取出し */
);
}
/*
*
*/
int main ( int argc, char *argv[] ) {
/* 値の設定 */
/*
* メモリセルの容量
*/
set_memory_value_at ( 100, 12 ); /* 100 番地のセルに 12 を記録する */
set_memory_value_at ( 101, 78 ); /* 100 番地のセルに 78 を記録する */
/*
* 100 番地の値と 101 番地の値の和を 102 番地にいれる
*/
/*
** この部分を完成させなさい
*/
/*
* 結果の出力
*/
print_memory_value ( 102 ); /* 102 番地のセルの内容を出力 */
return 0;
}
/*
*
*/
$ ./20191129-01-QQQQ.exe 102 番地のセルに記録されている数値は 90 です。 $