Download : sample-001.c
/*
* 2021/11/19 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
/*
* 2021/11/19 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
/*
* 2021/11/19 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
/*
* 2021/11/19 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
/*
* 2021/11/19 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 進数表現で 83e8c17e です。 変数 dvar のアドレスは 16 進数表現で 83e8c17f です。 変数 cvar に記録されている文字は c です。 変数 dvar に記録されている文字は D です。 cvar は X です。 dvar は y です。 $
Download : sample-006.c
/*
* 2021/11/19 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
/*
* 2021/11/19 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 進数表現で bd9adc5d です。 変数 dvar のアドレスは 16 進数表現で bd9adc5e です。 変数 evar のアドレスは 16 進数表現で bd9adc5f です。 cvar の所から記録されている文字列は (cD) です。 cvar に記録されている文字は c です。 dvar に記録されている文字は x です。 $
Download : sample-008.c
/*
* 2021/11/19 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 進数表現で abdc0350 です。 変数 carray[1] のアドレスは 16 進数表現で abdc0351 です。 変数 carray[2] のアドレスは 16 進数表現で abdc0352 です。 carray[0] の所から記録されている文字列は (cD) です。 carray[0] に記録されている文字は c です。 carray[1] に記録されている文字は x です。 $
Download : sample-009.c
/*
* 2021/11/19 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
/*
* 2021/11/19 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
/*
* 2021/11/19 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
/*
* 2021/11/19 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
/*
* 2021/11/19 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
/*
* 2021/11/19 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
/*
* 2021/11/19 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]=fd799530 (0,0)=fd799530 (0,1)=fd799531 (0,2)=fd799532 board[1]=fd799533 (1,0)=fd799533 (1,1)=fd799534 (1,2)=fd799535 board[2]=fd799536 (2,0)=fd799536 (2,1)=fd799537 (2,2)=fd799538 $
Download : sample-017.c
/*
* 2021/11/19 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
/*
* 2021/11/19 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 = 990ef108 (fact:前) n = 5, &n = 990ef0dc (fact:前) n = 4, &n = 990ef0ac (fact:前) n = 3, &n = 990ef07c (fact:前) n = 2, &n = 990ef04c (fact:前) n = 1, &n = 990ef01c (fact:前) n = 0, &n = 990eefec (fact:後) n = 0, &n = 990eefec (fact:後) n = 1, &n = 990ef01c (fact:後) n = 2, &n = 990ef04c (fact:後) n = 3, &n = 990ef07c (fact:後) n = 4, &n = 990ef0ac (fact:後) n = 5, &n = 990ef0dc fact(5)=120 $
Download : sample-019.c
/*
* 2021/11/19 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 = a3125b0c b = 4, &b = a3125b08 $
Download : sample-020.c
/*
* 2021/11/19 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 = add987c b = 4, &b = add9878 *(&b-1) = 0, &b-1 = add9874 a = 2 $
Download : sample-021.c
/*
* 2021/11/19 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 = ea724a0c *(&a+1) = 922827680, &a + 1 = ea724a10 *(&a+2) = 10962, &a + 2 = ea724a14 $
Download : sample-022.c
/*
* 2021/11/19 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]=-1271651328 subfunc ( 3,9,8,7,6 ); arg[0]=0 arg[1]=0 arg[2]=0 $
Download : sample-023.c
/*
* 2021/11/19 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
/*
* 2021/11/19 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
/*
* 2021/11/19 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
/*
* 2021/11/19 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
/*
* 2021/11/19 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 でした $
/*
* 課題 20211119-01
*
* 20211119 20211119-01-QQQQ.c
*
* 浮動小数点数の配列の要素内の数値の総和を求める。
* 配列を処理する関数を作りたい
* 配列名を関数の引数に指定して、関数内で配列を操作したい
*/
#include <stdio.h>
/*
* 浮動小数点数の配列の要素内の数値の総和を求める。
*
* 利用方法
* コンパイル
* cc -o BASENAME.exe 20211119-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
は、配列ではない
=> [] や * をつけて、初めて意味を持つので
サイズを指定する意味がない(一次元の場合は..)
逆に、
配列の要素を参照する場合は、
要素数がわからないといけないので、
要素数は、別に指定する必要がある
(固定でなければ..)
!! 配列名には、配列サイズの情報が含まれていない
!! 配列サイズは、(配列の場所を表す配列名とは別に) 指定する必要がある
*/
double sum = 0.0; /* 総和は最初は 0 */
int i; /* 配列の要素を参照する添字変数 */
for ( i = 0; i < size; i++ ) { /* i = 0 〜 sum - 1 の間.. */
sum = sum + ary[i];
/* 「sum += ary[i]」とも書きける */
/* a = a + x => a += x */
/* a = a * x => a *= x */
/* a = a + 1 => a += 1 => a++ */
}
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 );
/*
data[i] に、値を入力する => scanf で入力
配列 data の要素である data[i] は、浮動小数点数型の単純変数なので、
scanf を利用して、数値をキーボードから読み込み、
代入できる
*/
scanf ( "%lf", &data[i] );
}
sum = dsum ( data, ARY_SIZE ); /* 関数名とサイズ */
printf ( "入力されたデータの総和は %f です。\n", sum );
return 0;
}
/*
一つ配列を、
複数の関数で「共有」して処理する事が
効率が良いから
*/
#include <stdio.h>
/*
6 の約数の集合
= { 1, 2, 3, 6 }
*/
int main(int argc, char *argv[]) {
int s[4]; /* 6 の約数の集合を表す配列 */
int sum; /* 6 の約数の和を保存する変数 */
int i; /* 配列の要素を参照するための添え字変数 */
s[0] = 1;
s[1] = 2;
s[2] = 3;
s[3] = 6;
/* 配列 s で、「6 の約数の集合」を表現する */
/* 配列には、要素に順番がある */
/* 集合というよりは、列(リスト)と考えた方がよい */
/* 6 が完全数であることを確認 */
/* 「n が完全数」
<=> n の約数を全て加えると 2n になる
( 自分自身の除く約数を全て加えると n になる )
6 の約数 { 1, 2, 3, 6 }
1 + 2 + 3 + 6 = 12 = 2 * 6
1 + 2 + 3 = 6
*/
/*
配列 s の内容の総和を計算
*/
sum = 0; /* 総和を足しこむ変数を 0 に初期化 */
for ( i = 0; i < 4; i++ ) { /* 全ての配列要素をを参照するために添え字を変更 */
sum = sum + s[i]; /* 個々の要素を総和を表す変数に足しこむ */
/*
sum = sum + 1; i = 0 の時
sum = sum + 2; i = 1
sum = sum + 3;
sum = sum + 6;
*/
}
/* 変数 sum には、配列 s の全ての要素の和が計算される */
if ( sum == 2 * 6 ) { /* 完全数かどうかの確認 */
printf ( "6 は完全数\n" );
} else {
printf ( "6 は完全数でない\n" );
}
return 0;
}
#include <stdio.h>
#define ARY_SIZE 5
int main(int argc, char *argv[]) {
int ary[ARY_SIZE]; /* 整数型の要素を ARY_SIZE 個持つ配列 ary を宣言 */
/* ary[0] ? ary[ARY_SIZE-1] の配列要素が利用できる */
int i;
/* 配列要素の初期化 */
for ( i = 0; i < ARY_SIZE; i++ ) {
ary[i] = i*i; /* ary[i] == i^2 */
}
/* ary <- { 0, 1, 4, 9, 16 } */
/* 配列要素の中身の確認 */
for ( i = 0; i < ARY_SIZE; i++ ) {
printf ( "ary[%d] = %d\n", i, ary[i] );
}
/* ary[0] は *ary で表現する事ができる */
printf ( "ary[0] = %d, *ary = %d\n", ary[0], *ary );
*ary = -100;
printf ( "ary[0] = %d\n", ary[0] );
printf ( "*(ary + 1)=%d\n", *(ary + 1) );
printf ( "(ary + 1) の振る舞い\n" );
printf ( "(ary + 1)[0]=%d\n", (ary + 1)[0] );
printf ( "(ary + 1)[1]=%d\n", (ary + 1)[1] );
printf ( "(ary + 1)[2]=%d\n", (ary + 1)[2] );
/*
ary[0], ary[1], .. と比較して、
丁度、先頭の要素が欠けているようにみえる
*/
/*
前期に文字列のところで、同じ話をしている
cf.
文字列は「"abc"」のように「文字の並びを『"』で挟む」と作れる
"abc" は、文字 'a', 'b', 'c', EOS('\0') の四つからなる
文字列の先頭に * をつけると、先頭の文字が取り出せる
*"abc" -> 'a'
文字列に +1 すると、先頭の文字が一個欠けた文字列になる
*/
return 0;
}
#include <stdio.h>
/*
復習
文字列の性質
*/
int main(int argc, char *argv[]) {
printf ( "「\"abc\"」を利用して文字列「%s」を表現する\n",
"abc" );
/*
printf の書式で「%s」は、文字列を出力する書式
*/
/*
文字列の前に「*」を付ける事により、先頭の文字が取り出せる
*/
printf ( "「*\"abc\"」を利用して先頭の文字「%c」が取り出せる\n",
*"abc" );
/*
文字列に + 1 すると先頭の文字が欠けて短くなった文字列になる
*/
printf ( "「\"abc\"+1」を利用して先頭の文字が欠けた文字列「%s」ができる\n",
"abc" + 1 );
/*
文字列の k 番目 ( k = 0 ?.. ) を取り出すには
文字列の後ろに [k] をつける
*/
printf ( "「\"abc\"[1]」を利用して 1 番目(2 文字目)の文字「%c」が取り出せる\n",
"abc"[1] );
/*
文字列[整数値] <-> *(文字列 + 整数値)
*/
printf ( "「*(\"abc\"+1)」を利用して 1 番目(2 文字目)の文字「%c」が取り出せる\n",
*("abc"+1) );
return 0;
}
#include <stdio.h>
/*
復習
配列の性質
*/
#define ARY_SIZE 5
int main(int argc, char *argv[]) {
int ary[ARY_SIZE];
int i;
for ( i = 0; i < ARY_SIZE; i++ ) {
ary[i] = i * i * i;
}
/* ary <- { 0, 1, 8, 27, 64 } */
/*
配列名の前に「*」を付ける事により、先頭の要素が取り出せる
*/
printf ( "「*ary」を利用して先頭の要素「%d」が取り出せる\n",
*ary );
/*
配列名に + 1 すると先頭の要素が欠けて短くなった配列になる
*/
printf ( "「*(ary+1)」を利用して先頭の要素「%d」が取り出せる\n",
*(ary+1) );
/*
配列の k 番目 ( k = 0 ?.. ) を取り出すには
配列名の後ろに [k] をつける
*/
printf ( "「ary[1]」を利用して 1 番目(2 文字目)の要素「%d」が取り出せる\n",
ary[1] );
/*
配列名[整数値] <-> *(配列名 + 整数値)
*/
printf ( "「*(ary+1)」を利用して 1 番目(2 文字目)の要素「%d」が取り出せる\n",
*(ary+1) );
return 0;
}
#include <stdio.h>
#define ARY_SIZE 5
void sub ( int an[ARY_SIZE] ) {
/* 関数の仮引数変数には、実引数で指定された値がはいっている */
/* an <= ary */
int i;
for ( i = 0; i < ARY_SIZE; i++ ) {
printf ( "an[%d] = %d\n", i, an[i] );
/* an[i] => (an に ary (の値)が入っているので) ary[i] と同じ振る舞い */
}
}
int main(int argc, char *argv[]) {
int ary[ARY_SIZE];
int i;
for ( i = 0; i < ARY_SIZE; i++ ) {
ary[i] = 10 + i;
}
/*
ary <= { 10, 11, 12, 13, 14 }
*/
for ( i = 0; i < ARY_SIZE; i++ ) {
printf ( "ary[%d] = %d\n", i, ary[i] );
}
/*
ary という「配列名」は「(ポインター)値」を持っている
「値」は関数への引数に渡す事ができる
cf.
『文字列』を関数の引数に渡す事ができた..
*/
sub ( ary ); /* 関数の引数に「配列名」を指定 */
/* 「配列名」が表す「値」が実引数として渡される */
return 0;
}
#include <stdio.h>
void sub( int av ) {
printf ( "av = %d\n", av );
}
int main(int argc, char *argv[]) {
int i; /* 単純変数(配列や構造体に対して、構造を持たない変数 */
i = 123;
printf ( "i = %d\n", i );
sub ( i ); /* 変数の値(!! 「変数」を渡すのではなく、「変数の値」)を渡す */
return 0;
}
#include <stdio.h>
void sub( int av ) {
/* 変数 av には、関数呼び出し時の実引数の値が指定されている */
printf ( "av = %d\n", av );
/* 仮引数変数 av は「変数」なので、それの値を変更する事ができる */
av = av * 10; /* もともとの値を 10 倍 */
printf ( "av = %d\n", av );
}
int main(int argc, char *argv[]) {
int i; /* 単純変数(配列や構造体に対して、構造を持たない変数 */
i = 123;
printf ( "i = %d\n", i );
sub ( i ); /* 変数の値(!! 「変数」を渡すのではなく、「変数の値」)を渡す */
/* 再度 i の値を表示 : 関数呼び出しの影響をうけない */
/* 関数の引数に指定されるのは、引数の計算結果のコピーがわたされる */
printf ( "i = %d\n", i );
return 0;
}
#include <stdio.h>
typedef struct {
int x;
int y;
} Point2D;
void sub( Point2D av ) {
/* 変数 av には、関数呼び出し時の実引数の値が指定されている */
printf ( "av = (%d,%d)\n", av.x, av.y );
/* 仮引数変数 av は「変数」なので、それの値を変更する事ができる */
av.x = av.x * 10; /* もともとの値を 10 倍 */
printf ( "av = (%d,%d)\n", av.x, av.y );
}
int main(int argc, char *argv[]) {
Point2D p; /* p は構造体型の変数 */
p.x = 1;
p.y = -2; /* 点 p <- (1,-2) */
printf ( "p = (%d,%d)\n", p.x, p.y );
sub ( p ); /* 変数の値(!! 「変数」を渡すのではなく、「変数の値」)を渡す */
/* 再度 p の値を表示 : 関数呼び出しの影響をうけない */
/* 関数の引数に指定されるのは、引数の計算結果のコピーがわたされる */
printf ( "p = (%d,%d)\n", p.x, p.y );
return 0;
}
#include <stdio.h>
#define ARY_SIZE 2
void sub( int av[ARY_SIZE] ) {
/* 変数 av には、関数呼び出し時の実引数の値が指定されている */
printf ( "av = (%d,%d)\n", av[0], av[1] );
/* 仮引数変数 av は「変数」なので、それの値を変更する事ができる */
av = av + 1;
printf ( "av[0] = %d\n", av[0] );
}
int main(int argc, char *argv[]) {
int ary[ARY_SIZE];
ary[0] = 1;
ary[1] = -2;
/*
ary <- ( 1, -2 )
*/
printf ( "ary = (%d,%d)\n", ary[0], ary[1] );
sub ( ary ); /* 実引数に「配列名」を指定 */
/* 「配列名」は値を持つので、その値が渡される */
printf ( "ary = (%d,%d)\n", ary[0], ary[1] );
return 0;
}
#include <stdio.h>
#define ARY_SIZE 2
void sub( int av[ARY_SIZE] ) {
/* 変数 av には、関数呼び出し時の実引数の値が指定されている */
printf ( "av = (%d,%d)\n", av[0], av[1] );
av[0] = av[0] * 10; /* av[0] を書き換え */
/* ary[0] を書き換える事になる */
printf ( "av = (%d,%d)\n", av[0], av[1] );
}
int main(int argc, char *argv[]) {
int ary[ARY_SIZE];
ary[0] = 1;
ary[1] = -2;
/*
ary <- ( 1, -2 )
*/
printf ( "ary = (%d,%d)\n", ary[0], ary[1] );
sub ( ary ); /* 実引数に「配列名」を指定 */
/* 「配列名」は値を持つので、その値が渡される */
printf ( "ary = (%d,%d)\n", ary[0], ary[1] );
return 0;
}
/*
[振る舞い]
引数で渡した配列(を構成している変数)が、「直接」渡されて、
それが、変更かのようにみえる
[実際]
引数で渡したのは、「配列名が表す値」
配列の要素がある場所
(引数で指定されているの)場所の情報はがコピー
場所の情報を利用して、配列の要素(となる変数)を直接操作
cf. 単純変数や構造体との違い
単純変数や構造体の変数名を指定すると、その値がコピー
配列名を指定すると、配列の要素のコピーではなく
配列名がもつ、配列の要素の位置(情報)がコピーされる
原則(常に):
実引数で指定された値は、仮引数変数にコピーされる
仮引数変数の値を変更しても、呼び出し元に影響を与えない
*/
#include <stdio.h>
void sub( int av ) {
/* 変数 av には、関数呼び出し時の実引数の値が指定されている */
printf ( "av = %d\n", av );
/* 仮引数変数 av は「変数」なので、それの値を変更する事ができる */
av = av * 10; /* もともとの値を 10 倍 */
printf ( "av = %d\n", av );
}
#define ARY_SIZE 2
int main(int argc, char *argv[]) {
int ary[ARY_SIZE]; /* 配列の宣言 */
ary[0] = 123;
ary[1] = 987;
printf ( "ary[0] = %d\n", ary[0] );
sub ( ary[0] ); /* 要素の値(!! 「要素」を渡すのではなく、「要素の値」)を渡す */
/* 再度 ary[0] の値を表示 : 関数呼び出しの影響をうけない */
/* 関数の引数に指定されるのは、引数の計算結果のコピーがわたされる */
printf ( "ary[0] = %d\n", ary[0] );
/*
配列の要素が特別扱いされているわけではない
「配列名を引数に指定する」という表現が特殊
「配列名が持つ値(ポインター値)」が特殊
*/
return 0;
}
/*
今日の段階での ( 正確ではないが、簡単に理解可能な ) 内容
関数の引数に、配列名を指定する事により、
関数の中で、配列の要素(となる変数の内容)を変更できる
cf.
単純変数名や、構造体変数名を指定しても、
その変数や、構造体の要素の変数の内容は変更できない
*/
#include <stdio.h>
#define ARY_SIZE 2
typedef struct {
int ary[ARY_SIZE];
} SAry; /* 配列を要素とする構造体 */
void sub( SAry av ) {
/* 変数 av には、関数呼び出し時の実引数の値が指定されている */
printf ( "av = (%d,%d)\n", av.ary[0], av.ary[1] );
av.ary[0] = av.ary[0] * 10; /* av.ary[0] を書き換え */
printf ( "av = (%d,%d)\n", av.ary[0], av.ary[1] );
}
int main(int argc, char *argv[]) {
SAry s;
s.ary[0] = 1;
s.ary[1] = -2;
/*
s <- ( 1, -2 )
*/
printf ( "s = (%d,%d)\n", s.ary[0], s.ary[1] );
sub ( s ); /* 実引数に「構造体型の変数名」を指定 */
/* 構造体の要素の値がコピーされる */
printf ( "s = (%d,%d)\n", s.ary[0], s.ary[1] );
return 0;
}
/*
typedef struct {
int x;
int y;
} P;
P p;
p.x = 1;
p.y = -2;
+---------------------------+
| +---------------+ |
| x | 1 | | ----+
p | +---------------+ | |
| +---------------+ | |
| y | -2 | | --------+
| +---------------+ | | |
+---------------------------+ | |
| |
sub ( p ); | |
| |
| |コピー
+---------------------------+ | |
| +---------------+ | | |
| x | 1 | | <----+ |
av | +---------------+ | |
| +---------------+ | |
| y | -2 | | <--------+
| +---------------+ |
+---------------------------+
int a[2];
+----------+
a ------------> a[0] | 1 |
+-> +----------+
| a[1] | -2 |
| +----------+
|
a[0] = 1; |
a[1] = -2; |
|
sub ( a ) |
|
+-------+ |
av | *-------+ av = a
+-------+
*/
2021/11/26
前回(2021/11/19) の内容
配列 : (what) 同じ型の「変数」が並んだもの
個々の変数に、その型のデータを記録する
そのデータ型の「集まり(順序付き)」を表現
データ型
定数の表現
例 : 整数型 -> 123 / 文字型 -> 'c' / 浮動小数点数型 -> 1.23
そのデータ型の変数 ( 変数は型をもち、その型の定数値を保持する )
int vi;
vi = 123; /* 変数に定数値を代入する */
配列/構造体
変数の宣言の仕方があるだけ
# 定数の表現はない
!! 本来、「データ型」の対象 => 「(定数)値」の集合を指す
!! C 言語では、(残念な事に..) 「データの組み合わせ」はできない
!! 例 : 二次元平面の点を表すデータ型 ( x, y 座標の組 => (1,2) )
!! C 言語で、複雑なデータ型の「値」を表現するには ?
!! => (間接的に..) そのデータ型の値を保持できる「変数」を作り、
!! その変数に保存されている「値」を
!! その「変数の型の値」として扱う
例:
整数型
printf ( "%d\n", 1 ); 定数を直接操作
int i;
i=1;
printf ( "%d\n", i ); 変数を経由して操作
二次元の点の場合
typedef struct {
int x;
int y;
} Point;
Point p; /* Point 型の変数 p */
p = ( 1, 2 ); /* こう書く事ができれば良いのだが... */
/* => 定数を表現する方法がないのでダメ */
p.x = 1; /* 変数の一部の値を書き換える事により.. */
p.y = 2; /* 間接的に、変数 p に (1,2) 相当のデータを記録 */
/* 以下、(1,2) という点の操作を、
変数 p を利用して、行う事ができる */
配列を利用して、その型の要素をもつ有限集合を表現できる
配列の使い方(how)
配列(複数の変数をまとめたもの)の宣言
要素の型名 配列名[配列サイズ];
=>
1. 要素の型の変数が配列サイズ個だけ利用できるようになる
2. 配列名が利用できるようになる
配列の要素の参照(利用)
配列名[添え字]
「添え字」は、整数値をもつ式を指定できる
!! 式の中に「変数」を含める事ができる
!! => 変数を含む式を添え字とする配列を利用する文は、
!! 変数の値によって異なる振る舞いをする
!! !! もし、添え字に 整数定数しか指定できないなら、
!! !! 配列は、劣化した構造体にしかならない
!! !! しかし、配列の添え字には、(変数を含む)式が書けるので、
!! !! 構造体には(簡単には..)できない事が(簡単に..)できる
配列の配列も作れる
二次元の配列
要素の型名 配列名[配列サイズ1][配列サイズ2]
=> 配列サイズ1 x 配列サイズ2 個数の変数が利用可能になる
要素を参照する場合
配列名[添え字1][添え字2]
=> 一般に n 次元可能
[2021/11/26(資料は 2021/11/19 のもの利用)]
配列要素の参照方法
基本は添字参照「[]」を利用する
例 : int ary[5]; の時 ary[2] は 3 番目の要素の参照
間接参照「*」で先頭の要素が参照できる (文字列の時と同じ)
例 : *ary は ary[0] と同じ
配列名に整数値を加えると、配列の先頭の要素が「ない」ように振る舞う
例 : *(ary+3) は ary[3] と同じ (文字列の時と同じ)
配列要素参照「[]」と「*」の関係 (配列一般)
「ARY[INDEX]」と「*(ARY+INDEX)」は何時も同じ振舞いをする
!! 配列と文字列は同じようにふるまう
「配列名」の意味(詳細は後日)
!! 単独の「配列名」の意味
!! => 「ポインター定数値」である(あとで説明される..)
!! !! 過去のアルゴリズムでは配列を利用したものが多い
!! !! <= 添え字に変数が使える
!! !! => ポインター型の特徴
!! !! 配列を利用アルゴリズムは、ポインターを利用したアルゴリズム
!! !! C 言語より古い言語では、
!! !! 配列はつかえるがポインター型が使えなかった
!! !! => ポインター型の機能を実現するために、配列の代用した
!! !! C 言語では、ポインター型が直接扱えるので、本当なら、配列よりポインター型の話をくわしくすべき..
!! !! ただ、
!! !! 配列の方がわかりやすい
!! !! 配列の方が歴史がある
!! !! => 配列の話をする
「間接参照「*」や添字参照「[]」をする」事ができる「値」を表す
配列名は、「ある値」をもっていて
「その『値』」に「*」や「[]」をつける事により、
配列名をもつ配列(変数の集まり)の要素(変数)が参照できるようになる
「値」なので、関数に渡したり、関数の値にできる
「配列名」
配列の宣言すると、利用できるようになり
配列の要素を参照するために利用される
=> 配列の要素(変数)が利用できる
「配列名」も使えるように
値をもっていて、関数の引数に指定できる
[まとめ]
配列名は、
配列の要素の場所を表す値を持つ
値 => 関数の引数に指定して関数に渡す事ができる
その値をつかって、配列の要素を、関数内で操作(代入ができる)
配列の要素の参照の仕方
[] (添え字) 以外に * を使っても参照できて
=> 文字列と同じ振る舞い
[次回]
文字列を操作方法(2021/11/19 の内容)
=> メモリモデル(2021/11/26)
=> ポインター値の導入
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20211126-01.c
/*
* 20211126-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.
$ ./20211126-01-QQQQ.exe キーボードから一行の文字列を入力してください : 入力の中には 3 個の 'a' が含まれていました $