Download : sample-001.c
/*
* 2021/11/19 sample-001.c
*/
/*
* 多次元配列
*
* 利用方法
* コンパイル
* cc -c sample-001.c
* リンク
* cc -o sample-001.exe sample-001.c
* 実行
* ./sample-001.exe
*/
#include <stdio.h>
/*
* main
*
*/
int main( int argc, char *argv[] )
{
int a[3][4]; /* 二次元配列の宣言 3 x 4 (= 12) 個の変数を宣言 */
/* int a00, a01, .., a03, a10, .., a13, .., a23; と同様 */
int i;
int j;
a[0][0] = 0; /* 添字は、二つ必要 ( 二次なので.. ) で、0 から始まる */
a[2][3] = 6; /* 添字の大きさは、配列の大きさ - 1 まで */
/* 0 〜 2 と 0 〜 3 のかけ算表を作ってみる */
for ( i = 0; i < 3; i++ ) {
for ( j = 0; j < 4; j++ ) {
a[i][j] = i * j; /* a[i][j] 成分の値が i*j になるようにする */
}
}
printf ( "2 * 1 = %d\n", a[2][1] ); /* 2 と表示される筈 */
if ( a[1][2] == a[2][1] ) { /* 1 * 2 = 2 * 1 か ? */
printf ( "1 * 2 = 2 * 1 が成立\n" );
} else {
printf ( "1 * 2 = 2 * 1 が成立しない.. 何か変だ..\n" );
}
/* 0 〜 2 と 0 〜 3 のかけ算表を画面に表示 */
printf ( " * |" );
for ( j = 0; j < 4; j++ ) {
printf ( "%2d", j );
}
printf ( "\n" );
printf ( "---+---------\n" );
for ( i = 0; i < 3; i++ ) {
printf ( " %1d |", i );
for ( j = 0; j < 4; j++ ) {
printf ( "%2d", a[i][j] );
}
printf ( "\n" );
}
return 0;
}
$ ./sample-001.exe 2 * 1 = 2 1 * 2 = 2 * 1 が成立 * | 0 1 2 3 ---+--------- 0 | 0 0 0 0 1 | 0 1 2 3 2 | 0 2 4 6 $
Download : sample-002.c
/*
* 2021/11/19 sample-002.c
*/
/*
* 集合の操作は操作の集合
*
* 利用方法
* コンパイル
* cc -c sample-002.c
* リンク
* cc -o sample-002.exe sample-002.c
* 実行
* ./sample-002.exe
*/
#include <stdio.h>
/*
* main
*
*/
#define ARRAY_SIZE 5 /* 配列のサイズを 5 とする */
int main( int argc, char *argv[] )
{
int a[ARRAY_SIZE]; /* ARRAY_SIZE の配列の宣言 */
int i;
for ( i = 0; i < ARRAY_SIZE; i++ ) {
a[i] = 2 * i; /* 一桁の偶数の表を作る */
/* a = { 0, 2, 4, 6, 8 } */
}
/* 偶数を出力 */
for ( i = 0; i < ARRAY_SIZE; i++ ) {
printf ( "%d ", a[i] );
}
printf ( "\n" );
/* 全ての要素に 1 を加えれば奇数の表になる */
/* { 0, 2, 4, 6, 8 } -> { 1, 3, 5, 7, 9 } */
for ( i = 0; i < ARRAY_SIZE; i++ ) {
a[i] = a[i] + 1;
}
/* 奇数を出力 */
for ( i = 0; i < ARRAY_SIZE; i++ ) {
printf ( "%d ", a[i] );
}
printf ( "\n" );
return 0;
}
$ ./sample-002.exe 0 2 4 6 8 1 3 5 7 9 $
Download : sample-003.c
/*
* 2021/11/19 sample-003.c
*/
/*
* 文字配列と文字列 (1)
*
* 利用方法
* コンパイル
* cc -c sample-003.c
* リンク
* cc -o sample-003.exe sample-003.c
* 実行
* ./sample-003.exe
*/
#include <stdio.h>
/*
* main
*
*/
#define CSIZE 10
#define EOS '\0' /* End Of String */
int main( int argc, char *argv[] )
{
char cary[CSIZE];
cary[0] = 'a';
cary[1] = 'b';
cary[2] = 'c';
cary[3] = EOS;
/*
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
cary|'a'|'b'|'c'|EOS| ? | ? | ? | ? | ? | ? |
*/
printf ( "普通に文字列 \"abc\" を出力してみる : %s\n", "abc" );
/* 文字列を出力する場合の書式は「%s」を利用する */
printf ( "文字列の代りに文字配列を出力してみる : %s\n", cary );
/* 文字列の代りに文字配列名が使える */
return 0;
}
$ ./sample-003.exe 普通に文字列 "abc" を出力してみる : abc 文字列の代りに文字配列を出力してみる : abc $
Download : sample-004.c
/*
* 2021/11/19 sample-004.c
*/
/*
* 文字配列と文字列 (2)
*
* 利用方法
* コンパイル
* cc -c sample-004.c
* リンク
* cc -o sample-004.exe sample-004.c
* 実行
* ./sample-004.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| ? | ? | ? | ? |
*/
int i;
int l;
/*
* 文字列と文字配列
*/
printf ( "最初の cary = %s\n", cary );
/*
* 文字の変更
*/
cary[2] = 'A'; /* 文字列の途中の文字を差し替える */
/*
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
cary|'a'|'b'|'A'|'d'|'e'|EOS| ? | ? | ? | ? |
*/
printf ( "文字列の途中の文字を変更すると cary = %s\n", cary );
/*
* 文字の尻尾を切断
*/
cary[3] = EOS; /* 文字列の後ろを切断 */
/*
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
cary|'a'|'b'|'A'|EOS|'e'|EOS| ? | ? | ? | ? |
*/
printf ( "文字列を途中で切ると cary = %s\n", cary );
/*
* 文字を尻尾に追加
*/
cary[3] = 'X';
cary[5] = 'Y';
cary[6] = 'Z';
cary[7] = EOS; /* 文字列の最後に EOS を忘れずに !! */
/*
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
cary|'a'|'b'|'A'|'X'|'e'|'Y'|'Z'|EOS| ? | ? |
*/
printf ( "文字列の後ろに文字を追加すると cary = %s\n", cary );
/*
* 文字配列の出力
*/
printf ( "printf を使わず、文字配列を文字列のように出力すると : " );
for ( i = 0; cary[i] != EOS; i++ ) {
putchar ( cary[i] );
}
printf ( "と、なります。\n" );
/* 文字列の長さを求める */
for ( l = 0; cary[l] != EOS; l++ ) {
/* やる事は何もない (l を増やす事が目的) */
}
/* cary の中の文字列の長さは、変数 l に入る */
printf ( "文字列 %d の長さは %d です。\n", cary, l );
/*
* 途中の文字を削除
*/
for ( i = 3; cary[i] != EOS; i++ ) {
cary[i] = cary[i+1];
}
/* 文字列の途中(4 文字目)の文字('X')を削除 */
/*
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
cary|'a'|'b'|'A'|'X'|'e'|'Y'|'Z'|EOS| ? | ? |
| | | / / / /
|'a'|'b'|'A'|'e'|'Y'|'Z'|EOS|EOS| ? | ? |
*/
printf ( "文字列の途中の文字を削除すると cary = %s\n", cary );
return 0;
}
$ ./sample-004.exe 最初の cary = abcde 文字列の途中の文字を変更すると cary = abAde 文字列を途中で切ると cary = abA 文字列の後ろに文字を追加すると cary = abAXeYZ printf を使わず、文字配列を文字列のように出力すると : abAXeYZと、なります。 文字列 -443253904 の長さは 7 です。 文字列の途中の文字を削除すると cary = abAeYZ $
Download : sample-005.c
/*
* 2021/11/19 sample-005.c
*/
/*
* 配列の要素の参照
*
* 利用方法
* コンパイル
* cc -c sample-005.c
* リンク
* cc -o sample-005.exe sample-005.c
* 実行
* ./sample-005.exe
*/
#include <stdio.h>
/*
* main
*
*/
#define ARRAY_SIZE 10
int main( int argc, char *argv[] )
{
int iary[ARRAY_SIZE];
int i;
/* 配列の初期化 */
/* iary[i] = i*i */
for ( i = 0; i < ARRAY_SIZE; i++ ) {
iary[i] = i*i;
}
/*
これで、iary は i=0〜9 なら、関数 f(x)=x^2 と同じ振舞いをする
*/
/*
配列参照 : 普通の「添字参照」の場合
*/
for ( i = 0; i < ARRAY_SIZE; i++ ) {
printf ( "iary[%d]=%d\n", i, iary[i] );
}
/*
配列参照 : 「間接参照("*" の利用)」の場合
*(iary + i) == iary[i]
*/
for ( i = 0; i < ARRAY_SIZE; i++ ) {
printf ( "*(iary + %d)=%d\n", i, *(iary + i) );
}
/*
配列参照 : 配列名を使った計算 ( 添字を 1 からスタート )
(iary-1)[i] = *((iary - 1) + i) == *(iary + (i-1)) = iary[i-1]
*/
for ( i = 1; i <= ARRAY_SIZE; i++ ) {
printf ( "(iary-1)[i]=%d, iary[i-1]=%d\n", i, (iary-1)[i], i, iary[i-1] );
}
return 0;
}
$ ./sample-005.exe iary[0]=0 iary[1]=1 iary[2]=4 iary[3]=9 iary[4]=16 iary[5]=25 iary[6]=36 iary[7]=49 iary[8]=64 iary[9]=81 *(iary + 0)=0 *(iary + 1)=1 *(iary + 2)=4 *(iary + 3)=9 *(iary + 4)=16 *(iary + 5)=25 *(iary + 6)=36 *(iary + 7)=49 *(iary + 8)=64 *(iary + 9)=81 (iary-1)[i]=1, iary[i-1]=0 (iary-1)[i]=2, iary[i-1]=1 (iary-1)[i]=3, iary[i-1]=4 (iary-1)[i]=4, iary[i-1]=9 (iary-1)[i]=5, iary[i-1]=16 (iary-1)[i]=6, iary[i-1]=25 (iary-1)[i]=7, iary[i-1]=36 (iary-1)[i]=8, iary[i-1]=49 (iary-1)[i]=9, iary[i-1]=64 (iary-1)[i]=10, iary[i-1]=81 $
Download : sample-006.c
/*
* 2021/11/19 sample-006.c
*/
/*
* 配列名の関数への引渡し
*
* 利用方法
* コンパイル
* cc -c sample-006.c
* リンク
* cc -o sample-006.exe sample-006.c
* 実行
* ./sample-006.exe
*/
#include <stdio.h>
/*
* 配列サイズ
*/
#define ARRAY_SIZE 10
/*
* 引数に配列を持つ関数
*/
void print_array ( int a[ARRAY_SIZE] ) {
int i;
for ( i = 0; i < ARRAY_SIZE; i++ ) {
printf ( "a[%d]=%d, %d*%d = %d\n", i, a[i], i, i, i*i );
}
}
/*
* main
*
*/
int main( int argc, char *argv[] )
{
int iary[ARRAY_SIZE];
int i;
/* 配列の初期化 */
/* iary[i] = i*i */
for ( i = 0; i < ARRAY_SIZE; i++ ) {
iary[i] = i*i;
}
/*
これで、iary は i=0〜9 なら、関数 f(x)=x^2 と同じ振舞いをする
*/
print_array ( iary ); /* 関数の引数に「配列名」を指定できる */
return 0;
}
$ ./sample-006.exe a[0]=0, 0*0 = 0 a[1]=1, 1*1 = 1 a[2]=4, 2*2 = 4 a[3]=9, 3*3 = 9 a[4]=16, 4*4 = 16 a[5]=25, 5*5 = 25 a[6]=36, 6*6 = 36 a[7]=49, 7*7 = 49 a[8]=64, 8*8 = 64 a[9]=81, 9*9 = 81 $
Download : sample-007.c
/*
* 2021/11/19 sample-007.c
*/
/*
* 配列名の関数への引渡し(2)
*
* 利用方法
* コンパイル
* cc -c sample-007.c
* リンク
* cc -o sample-007.exe sample-007.c
* 実行
* ./sample-007.exe
*/
#include <stdio.h>
/*
* 配列サイズ
*/
#define I_ARRAY_SIZE 10
#define J_ARRAY_SIZE 5
/*
* 配列のサイズは、省略可能
* サイズの異る配列に対しても同じ関数が利用できる !!
*/
void print_n_array ( int a[], int size ) {
int i;
for ( i = 0; i < size; i++ ) {
printf ( "a[%d]=%d\n", i, a[i] );
}
}
/*
* main
*
*/
int main( int argc, char *argv[] )
{
int iary[I_ARRAY_SIZE];
int jary[J_ARRAY_SIZE];
int i;
/* 配列の初期化 */
/* iary[i] = i*i */
for ( i = 0; i < I_ARRAY_SIZE; i++ ) {
iary[i] = i*i;
}
/* jary[i] = i*i*i */
for ( i = 0; i < J_ARRAY_SIZE; i++ ) {
jary[i] = i*i*i;
}
printf ( "iary: 0 〜 %d\n", I_ARRAY_SIZE - 1 );
print_n_array ( iary, I_ARRAY_SIZE ); /* iary の内容を出力 */
printf ( "jary: 0 〜 %d\n", J_ARRAY_SIZE - 1 );
print_n_array ( jary, J_ARRAY_SIZE ); /* jary の内容を出力 */
/* 配列の一部の表示も可能 */
printf ( "iary: 0 〜 %d\n", J_ARRAY_SIZE - 1 );
print_n_array ( iary, J_ARRAY_SIZE );
/* 配列の途中からの表示も可能 */
printf ( "iary: %d 〜 %d\n", J_ARRAY_SIZE, I_ARRAY_SIZE - 1 );
print_n_array ( iary + J_ARRAY_SIZE, I_ARRAY_SIZE - J_ARRAY_SIZE );
return 0;
}
$ ./sample-007.exe iary: 0 〜 9 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 jary: 0 〜 4 a[0]=0 a[1]=1 a[2]=8 a[3]=27 a[4]=64 iary: 0 〜 4 a[0]=0 a[1]=1 a[2]=4 a[3]=9 a[4]=16 iary: 5 〜 9 a[0]=25 a[1]=36 a[2]=49 a[3]=64 a[4]=81 $
Download : sample-008.c
/*
* 2021/11/19 sample-008.c
*/
/*
* 配列名の関数への引渡し(3)
*
* 利用方法
* コンパイル
* cc -c sample-008.c
* リンク
* cc -o sample-008.exe sample-008.c
* 実行
* ./sample-008.exe
*/
#include <stdio.h>
/*
* 配列サイズ
*/
#define I_ARRAY_SIZE 10
/*
* 1 次元配列 (a[]) の仮引数変数宣言は、「*a」形の宣言でも良い
*/
void print_n_array ( int *a, int size ) {
int i;
for ( i = 0; i < size; i++ ) {
printf ( "a[%d]=%d\n", i, a[i] );
}
}
/*
* main
*
*/
int main( int argc, char *argv[] )
{
int iary[I_ARRAY_SIZE];
int i;
/* 配列の初期化 */
/* iary[i] = i*i */
for ( i = 0; i < I_ARRAY_SIZE; i++ ) {
iary[i] = i*i;
}
printf ( "iary: 0 〜 %d\n", I_ARRAY_SIZE - 1 );
print_n_array ( iary, I_ARRAY_SIZE ); /* iary の内容を出力 */
return 0;
}
$ ./sample-008.exe iary: 0 〜 9 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 $
Download : sample-009.c
/*
* 2021/11/19 sample-009.c
*/
/*
* 配列名の関数への引渡し(4)
*
* 利用方法
* コンパイル
* cc -c sample-009.c
* リンク
* cc -o sample-009.exe sample-009.c
* 実行
* ./sample-009.exe
*/
#include <stdio.h>
/*
* 配列サイズ
*/
#define I_ARRAY_SIZE 10
/*
* 1 次元配列 (a[]) の仮引数変数宣言は、「*a」形の宣言でも良い
*/
void print_n_array ( int *a, int size ) {
int i;
for ( i = 0; i < size; i++ ) {
printf ( "a[%d]=%d\n", i, a[i] );
}
}
/*
* 配列引数の要素の値を書き換える
*/
void change_at ( int *a, int pos, int value ) {
a[pos] = value;
}
/*
* main
*
*/
int main( int argc, char *argv[] )
{
int iary[I_ARRAY_SIZE];
int i;
/* 配列の初期化 */
/* iary[i] = i*i */
for ( i = 0; i < I_ARRAY_SIZE; i++ ) {
iary[i] = i*i;
}
printf ( "iary: 0 〜 %d\n", I_ARRAY_SIZE - 1 );
print_n_array ( iary, I_ARRAY_SIZE ); /* iary の内容を出力 */
printf ( "%d 番目の要素を %d に書き換える\n", 5, 100 );
change_at ( iary, 5, 100 );
printf ( "iary: 0 〜 %d\n", I_ARRAY_SIZE - 1 );
print_n_array ( iary, I_ARRAY_SIZE ); /* iary の内容を出力 */
return 0;
}
$ ./sample-009.exe iary: 0 〜 9 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 5 番目の要素を 100 に書き換える iary: 0 〜 9 a[0]=0 a[1]=1 a[2]=4 a[3]=9 a[4]=16 a[5]=100 a[6]=36 a[7]=49 a[8]=64 a[9]=81 $
Download : sample-011.c
/*
* 2021/11/19 sample-011.c
*/
/*
* 文字列の入力\n *\tscanf の「%s」で文字列を入力する事ができる
*
* 利用方法
* コンパイル
* cc -c sample-011.c
* リンク
* cc -o sample-011.exe sample-011.c
* 実行
* ./sample-011.exe
*/
#include <stdio.h>
/*
* main 関数
*/
#define LINE_SIZE 128 /* 入力する文字列より大きなサイズにする */
int main ( int argc, char *argv[] ) {
char line[LINE_SIZE]; /* 入力する文字列を収める文字型配列 */
printf ( "キーボードから、「空白(' ')を含んだ、適当な長さの文字列」と入力して Enter キーを押してください。: " );
scanf ( "%s", line ); /* 書式は「%s」で、文字型配列名を直接使う(&)は不要 */
printf ( "あなたが入力した文字列は「%s」です。\n", line );
/* 空白文字(空白/タブ/改行)があると、「文字列の区切」とみなされる */
return 0;
}
空白(' ')を含んだ、適当な長さの文字列
$ ./sample-011.exe < sample-011.in
キーボードから、「空白(' ')を含んだ、適当な長さの文字列」と入力して Enter キーを押してください。: 空白('
あなたが入力した文字列は「空白('」です。
$
Download : sample-012.c
/*
* 2021/11/19 sample-012.c
*/
/*
* 文字列の入力 (2)
* gets で文字列を入力する事ができる
*
* 利用方法
* コンパイル
* cc -c sample-012.c
* リンク
* cc -o sample-012.exe sample-012.c
* 実行
* ./sample-012.exe
*/
#include <stdio.h>
/*
* main 関数
*/
#define LINE_SIZE 128 /* 入力する文字列より大きなサイズにする */
int main ( int argc, char *argv[] ) {
char line[LINE_SIZE]; /* 入力する文字列を収める文字型配列 */
printf ( "キーボードから、「空白(' ')を含んだ、適当な長さの文字列」と入力して Enter キーを押してください。: " );
gets ( line );
/* gets では、「一行(改行の直前迄:改行含まず)」の文字列が入力される */
printf ( "あなたが入力した文字列は「%s」です。\n", line );
/* gets は一行(改行)までを入力する */
return 0;
}
空白(' ')を含んだ、適当な長さの文字列
$ ./sample-012.exe < sample-012.in
キーボードから、「空白(' ')を含んだ、適当な長さの文字列」と入力して Enter キーを押してください。: 空白(' ')を含んだ、適当な長さの文字列
あなたが入力した文字列は「空白(' ')を含んだ、適当な長さの文字列」です。
$
Download : sample-013.c
/*
* 2021/11/19 sample-013.c
*/
/*
* 文字列の入力 (3)\n *\tfgets で文字列を入力する事ができる
*
* 利用方法
* コンパイル
* cc -c sample-013.c
* リンク
* cc -o sample-013.exe sample-013.c
* 実行
* ./sample-013.exe
*/
#include <stdio.h>
/*
* main 関数
*/
#define LINE_SIZE 128 /* 入力する文字列より大きなサイズにする */
int main ( int argc, char *argv[] ) {
char line[LINE_SIZE]; /* 入力する文字列を収める文字型配列 */
printf ( "キーボードから、「空白(' ')を含んだ、適当な長さの文字列」と入力して Enter キーを押してください。: " );
fgets ( line, LINE_SIZE, stdin );
/* 入力先は、「標準入力 (stdin)」となる */
/* fgets では、文字列サイズが指定できる (安全) */
/* 指定したサイズより長い文字列は、入力が「待たされ」る */
printf ( "あなたが入力した文字列は「%s」です。\n", line );
/* 入力文字列内には、「改行」も含まれる */
return 0;
}
空白(' ')を含んだ、適当な長さの文字列
$ ./sample-013.exe < sample-013.in
キーボードから、「空白(' ')を含んだ、適当な長さの文字列」と入力して Enter キーを押してください。: 空白(' ')を含んだ、適当な長さの文字列
あなたが入力した文字列は「空白(' ')を含んだ、適当な長さの文字列
」です。
$
Download : sample-021.c
/*
* 2021/11/19 sample-021.c
*/
/*
* sizeof 演算子\n *\t型名を指定する事により、そのサイズ(byte 単位)を得る事ができる
*
* 利用方法
* コンパイル
* cc -c sample-021.c
* リンク
* cc -o sample-021.exe sample-021.c
* 実行
* ./sample-021.exe
*/
#include <stdio.h>
/*
* main 関数
*/
int main ( int argc, char *argv[] ) {
printf ( "sizeof ( char ) = %d\n", sizeof ( char ) );
printf ( "sizeof ( int ) = %d\n", sizeof ( int ) );
printf ( "sizeof ( double ) = %d\n", sizeof ( double ) );
return 0;
}
$ ./sample-021.exe sizeof ( char ) = 1 sizeof ( int ) = 4 sizeof ( double ) = 8 $
Download : sample-022.c
/*
* 2021/11/19 sample-022.c
*/
/*
* sizeof 演算子 (2)\n *\t変数名を指定する事により、そのサイズ(byte 単位)を得る事ができる
*
* 利用方法
* コンパイル
* cc -c sample-022.c
* リンク
* cc -o sample-022.exe sample-022.c
* 実行
* ./sample-022.exe
*/
#include <stdio.h>
/*
* main 関数
*/
int main ( int argc, char *argv[] ) {
char cvar;
int ivar;
double dvar;
printf ( "sizeof ( cvar ) = %d\n", sizeof ( cvar ) );
printf ( "sizeof ( ivar ) = %d\n", sizeof ( ivar ) );
printf ( "sizeof ( dvar ) = %d\n", sizeof ( dvar ) );
return 0;
}
$ ./sample-022.exe sizeof ( cvar ) = 1 sizeof ( ivar ) = 4 sizeof ( dvar ) = 8 $
Download : sample-023.c
/*
* 2021/11/19 sample-023.c
*/
/*
* sizeof 演算子 (3)\n *\t配列名を指定する事により、そのサイズ(byte 単位)を得る事ができる
*
* 利用方法
* コンパイル
* cc -c sample-023.c
* リンク
* cc -o sample-023.exe sample-023.c
* 実行
* ./sample-023.exe
*/
#include <stdio.h>
/*
* main 関数
*/
int main ( int argc, char *argv[] ) {
char cary[100];
int iary[100];
double dary[100];
printf ( "sizeof ( cary ) = %d\n", sizeof ( cary ) );
printf ( "sizeof ( iary ) = %d\n", sizeof ( iary ) );
printf ( "sizeof ( dary ) = %d\n", sizeof ( dary ) );
return 0;
}
$ ./sample-023.exe sizeof ( cary ) = 100 sizeof ( iary ) = 400 sizeof ( dary ) = 800 $
Download : sample-024.c
/*
* 2021/11/19 sample-024.c
*/
/*
* sizeof 演算子 (4)\n *\t値を指定する事もできる
*
* 利用方法
* コンパイル
* cc -c sample-024.c
* リンク
* cc -o sample-024.exe sample-024.c
* 実行
* ./sample-024.exe
*/
#include <stdio.h>
/*
* main 関数
*/
int main ( int argc, char *argv[] ) {
printf ( "sizeof ( 'a' ) = %d\n", sizeof ( 'a' ) );
/* sizeof ( int ) [整数] になっている */
printf ( "sizeof ( 123 ) = %d\n", sizeof ( 123 ) );
printf ( "sizeof ( 12.3 ) = %d\n", sizeof ( 12.3 ) );
return 0;
}
$ ./sample-024.exe sizeof ( 'a' ) = 4 sizeof ( 123 ) = 4 sizeof ( 12.3 ) = 8 $
Download : sample-025.c
/*
* 2021/11/19 sample-025.c
*/
/*
* sizeof 演算子 (5)\n *\t式のサイズも得られる\n *\tchar 型のデータは、計算の時に、int 型に昇格する
*
* 利用方法
* コンパイル
* cc -c sample-025.c
* リンク
* cc -o sample-025.exe sample-025.c
* 実行
* ./sample-025.exe
*/
#include <stdio.h>
/*
* main 関数
*/
int main ( int argc, char *argv[] ) {
char ch;
char dh;
printf ( "sizeof ( ch ) = %d\n", sizeof ( ch ) );
/* sizeof ( char ) [文字] になっている */
printf ( "sizeof ( ch + dh ) = %d\n", sizeof ( ch + dh ) );
/* sizeof ( int ) [整数] になっている */
/* 無条件の型の昇格がおきている */
return 0;
}
$ ./sample-025.exe sizeof ( ch ) = 1 sizeof ( ch + dh ) = 4 $
Download : sample-026.c
/*
* 2021/11/19 sample-026.c
*/
/*
* 型の昇格\n *\tint 型から double 型への変換
*
* 利用方法
* コンパイル
* cc -c sample-026.c
* リンク
* cc -o sample-026.exe sample-026.c
* 実行
* ./sample-026.exe
*/
#include <stdio.h>
/*
* main 関数
*/
int main ( int argc, char *argv[] ) {
int num;
int mum;
printf ( "sizeof ( num ) = %d\n", sizeof ( num ) );
printf ( "sizeof ( num + 'A' ) = %d\n", sizeof ( num + 'A' ) );
printf ( "sizeof ( num + mum ) = %d\n", sizeof ( num + mum ) );
printf ( "sizeof ( num + 1.0 ) = %d\n", sizeof ( num + 1.0 ) );
return 0;
}
$ ./sample-026.exe sizeof ( num ) = 4 sizeof ( num + 'A' ) = 4 sizeof ( num + mum ) = 4 sizeof ( num + 1.0 ) = 8 $
Download : sample-027.c
/*
* 2021/11/19 sample-027.c
*/
/*
* 型の変換\n *\t代入では、必要に応じて型変換が行わる
*
* 利用方法
* コンパイル
* cc -c sample-027.c
* リンク
* cc -o sample-027.exe sample-027.c
* 実行
* ./sample-027.exe
*/
#include <stdio.h>
/*
* main 関数
*/
int main ( int argc, char *argv[] ) {
char ch = 'A'; /* そもそも 'A' は int 型 */
int num = 'A';
double fp = 'A'; /* int 型から double 型へ */
ch = ch - 'A' + 'a'; /* int 型から char 型へ */
ch = num; /* int 型から char 型へ */
num = fp; /* double 型から int 型へ */
printf ( "ch = %c\n", ch );
printf ( "num = %d\n", num );
printf ( "fp = %f\n", fp );
return 0;
}
$ ./sample-027.exe ch = A num = 65 fp = 65.000000 $
Download : sample-028.c
/*
* 2021/11/19 sample-028.c
*/
/*
* 型の変換 (2)\n *\tサイズの大きい方から、小さい方への変換は危険
*
* 利用方法
* コンパイル
* cc -c sample-028.c
* リンク
* cc -o sample-028.exe sample-028.c
* 実行
* ./sample-028.exe
*/
#include <stdio.h>
/*
* main 関数
*/
int main ( int argc, char *argv[] ) {
char ch = 'A';
int num = 'A';
double fp = 'A';
/* 個々に適切な値を入れれば問題はない */
printf ( "[適切な値]\n" );
printf ( "\tch = '%c' [%d]\n", ch, ch );
printf ( "\tnum = %d\n", num );
printf ( "\tfp = %f\n", fp );
/* char 型に収まらないサイズの値を代入すると ?? */
num = 1000; /* 1000 > 255 なので、1000 は char 型に収まらない */
ch = num; /* 代入を行うとどうなるか */
printf ( "[char に大きな値]\n" );
printf ( "\tch = '%c' [%d]\n", ch, ch );
printf ( "\tnum = %d\n", num );
/* int 型に収まらないサイズの値を代入すると ?? */
fp = 1000000000000;
num = fp;
ch = fp;
printf ( "[int に大きな値]\n" );
printf ( "\tch = '%c' [%d]\n", ch, ch );
printf ( "\tnum = %d\n", num );
printf ( "\tfp = %f\n", fp );
return 0;
}
$ ./sample-028.exe [適切な値] ch = 'A' [65] num = 65 fp = 65.000000 [char に大きな値] ch = '?' [-24] num = 1000 [int に大きな値] ch = ' ' [0] num = -2147483648 fp = 1000000000000.000000 $
/*
* 課題 20211112-01
*
* 20211112 20211112-01-QQQQ.c
*
* 複素数型の四則(構造体の応用)
*/
#include <stdio.h>
/*
* 複素数型の定義と計算
*
* 利用方法
* コンパイル
* cc -Ic:\usr\c\include -o BASENAME.exe 20211112-01-QQQQ.c
* 実行
* BASENAME
*/
#include <stdio.h>
/*
* 複素数型を表す Complex の定義
*
* 複素数 z は、二つの実数 x, y を用いて
* z = x + yi ( i は虚数単位 )
* と表現できる。
* C 言語では実数を表すのに浮動小数点数型の double を用いる
* 型名 ( Complex ) を大文字で始めるのは「ソフトウェア概論ルール」
*/
typedef struct {
double real; /* 実部 */
double imaginary; /* 虚部 */
} Complex; /* 複素数型 */
/*
* Complex make_Complex ( double x, double y )
* Complex 型の数を作り、返す
* x, y -> z = x + yi
*/
Complex make_Complex ( double x, double y ) {
Complex newComplex; /* 新しく作られる複素数 */
newComplex.real = x; /* 新しく作られた複素数の実部は x */
newComplex.imaginary = y; /* 新しく作られた複素数の実部は y */
return newComplex; /* 新しく作られる複素数を値として返す */
}
/*
* double real_part ( Complex z )
* Complex 型の数の実部を返す
* z = x + yi -> x
*/
double real_part ( Complex z ) {
return z.real; /* 関数で表現するのは、抽象化を進めるため */
}
/*
* double imaginary_part ( Complex z )
* Complex 型の数の実部を返す
* z = x + yi -> x
*/
double imaginary_part ( Complex z ) {
return z.imaginary;
}
/*
* print_Complex ( Complex z )
* Complex 型の数の出力
* z = x + y i だが、y < 0 の時は z = x - (-y) i となるように工夫
*/
void print_Complex ( Complex z ) {
if ( z.imaginary > 0.0 ) {
printf ( "%f + %f i", z.real, z.imaginary );
/* 本当なら z.real, z.imaginary が 0 の時 */
/* z.imaginary が 1 の時は表現を工夫した方がよいが.. */
} else {
printf ( "%f - %f i", z.real, - z.imaginary );
}
}
/* 複素数の四則を実現する */
/*
* Complex add_Complex ( Complex z1, Complex z2 )
* Complex 型の数の足し算
* z1 = x1 + y1 i
* z2 = x2 + y2 i
* -> z1 + z2 = ( x1 + x2 ) + ( y1 + y2 ) i
*/
Complex add_Complex ( Complex z1, Complex z2 ) {
Complex result;
/* 複素数の和の実部は、実部の和 */
result.real = z1.real + z2.real;
/* 複素数の和の虚部は、虚部の和 */
result.imaginary = z1.imaginary + z2.imaginary;
return result;
}
/*
* Complex sub_Complex ( Complex z1, Complex z2 )
* Complex 型の数の引き算
* z1 = x1 + y1 i
* z2 = x2 + y2 i
* -> z1 - z2 = ( x1 - x2 ) + ( y1 - y2 ) i
*/
Complex sub_Complex ( Complex z1, Complex z2 ) {
Complex result;
/* 複素数の差の実部は、実部の差 */
result.real = z1.real - z2.real;
/* 複素数の差の虚部は、虚部の差 */
result.imaginary = z1.imaginary - z2.imaginary;
return result;
}
/*
* Complex mul_Complex ( Complex z1, Complex z2 )
* Complex 型の数のかけ算
* z1 = x1 + y1 i
* z2 = x2 + y2 i
* の時
* z1 * z2 = (x1 * x2 - y1 * y2) + (x1 * y2 + x2 * y1) i
* = (x1 * x2 + i^2 * y1 * y2) + (x1 * y2 + x2 * y1) i
*/
Complex mul_Complex ( Complex z1, Complex z2 ) {
Complex result;
result.real = z1.real * z2.real - z1.imaginary * z2.imaginary;
result.imaginary = z1.real * z2.imaginary + z2.real * z1.imaginary;
return result;
}
/*
* Complex div_Complex ( Complex z1, Complex z2 )
* Complex 型の数の割り算
* z1 = x1 + y1 i
* z2 = x2 + y2 i
* の時
* z1 / z2 = ( x1 + y1 i ) / ( x2 + y2 i )
* = ( x1 + y1 i )( x2 - y2 i ) / ( x2 + y2 i )( x2 - y2 i )
* = ( x1 * x2 + y1 * y2) / ( x2^2 + y2^2 )
* + ( (- x1 * y2 + x2 * y1) / ( x2^2 + y2^2 ) ) i
*/
Complex div_Complex ( Complex z1, Complex z2 ) {
Complex result;
double denominator = z2.real * z2.real + z2.imaginary *z2.imaginary;
/* 実部、虚部の割る数 |z2|^2 を予め計算しておく */
result.real = (z1.real*z2.real + z1.imaginary * z2.imaginary ) / denominator;
result.imaginary = ( - z1.real * z2.imaginary + z1.imaginary * z2.real ) / denominator;
return result;
}
/*
* print_result 演算結果を出力する
*/
void print_result ( Complex z1, Complex z2, char *operator, Complex z ) {
print_Complex ( z1 );
printf ( " と、 " );
print_Complex ( z2 );
printf ( " との、%s は ", operator );
print_Complex ( z );
printf ( " です。\n" );
}
/*
* main
*/
int main( int argc, char *argv[] )
{
Complex z1 = make_Complex ( 20.0, -15.0 ); /* z1 = 20 - 15i */
Complex z2 = make_Complex ( 1.0, 2.0 ); /* z2 = 1 + 2i */
/* 和の出力 */
print_result ( z1, z2, "和", add_Complex ( z1, z2 ) );
/* 差の出力 */
print_result ( z1, z2, "差", sub_Complex ( z1, z2 ) );
/* 積の出力 */
print_result ( z1, z2, "積", mul_Complex ( z1, z2 ) );
/* 商の出力 */
print_result ( z1, z2, "商", div_Complex ( z1, z2 ) );
return 0;
}
/*
* 課題 20211112-02
*
* 20211112 20211112-02-QQQQ.c
*
* 二次元行列型の定義と計算
*/
#include <stdio.h>
/*
*
*/
#define DIMENSION 2 /* 二次元 */
/*
* 行列 A は、2 x 2 = 4 の要素をもっている
*
* A = ( 1 2 ) = ( a[0][0] a[0][1] )
* 3 4 a[1][0] a[1][1]
*
*/
typedef struct {
double a[DIMENSION][DIMENSION]; /* 二次元の行列の要素は 2 x 2 */
} Matrix2D; /* Matrix2D 型の宣言 */
/*
typedef double Matrix2D[DIMENSION][DIMENSION]
としない理由は、来週説明
/*
* Matrix2D make_Matrix2D ( double a, double b, double c, double d )
* 「行列」を作成する
*
* A = ( a b ) = ( a[0][0], a[0][1] )
* ( c d ) ( a[1][0], a[1][1] )
*/
Matrix2D make_Matrix2D ( double a, double b, double c, double d ) {
Matrix2D newMatrix2D; /* 新しい行列 */
newMatrix2D.a[0][0] = a;
newMatrix2D.a[0][1] = b;
newMatrix2D.a[1][0] = c;
newMatrix2D.a[1][1] = d;
return newMatrix2D;
}
/*
* void print_Matrix2D ( Matrix2D ary );
* 「行列」を表示する (表示の都合上、常に独立した行に出力する)
* Matrix2D ary; 二次元行列
*/
void print_Matrix2D ( Matrix2D ary ) {
int r; /* 行 ( row ) */
int c; /* 列 ( colomun ) */
for ( r = 0; r < DIMENSION; r++ ) {
printf ( "(" );
for ( c = 0; c < DIMENSION; c++ ) {
printf ( " %10.5f", ary.a[r][c] );
/*
* [注意] %10.5f は %f と同じく浮動小数点数を出力するが
* 「全体の桁数は 10 桁、小数点数以下は 5 桁にする」
* という「表示上の指定」も加わっている
* 詳しくは google で「printf 書式」で検索
*/
}
printf ( " )\n" );
}
}
/*
* Matrix2D add_Matrix2D ( Matrix2D a1, Matrix2D a2 );
* 「行列」の和
*
* ( a b ) + ( e f ) = ( a + e b + f )
* ( c d ) ( g h ) ( c + g g + h )
*/
Matrix2D add_Matrix2D ( Matrix2D a1, Matrix2D a2 ) {
Matrix2D result; /* 計算結果 */
int r; /* 行 ( row ) */
int c; /* 列 ( colomun ) */
for ( r = 0; r < DIMENSION; r++ ) {
for ( c = 0; c < DIMENSION; c++ ) {
result.a[r][c] = a1.a[r][c] + a2.a[r][c];
}
}
return result;
}
/*
* Matrix2D sub_Matrix2D ( Matrix2D a1, Matrix2D a2 );
* 「行列」の差
*
* ( a b ) - ( e f ) = ( a - e b - f )
* ( c d ) ( g h ) ( c - g g - h )
*/
Matrix2D sub_Matrix2D ( Matrix2D a1, Matrix2D a2 ) {
Matrix2D result; /* 計算結果 */
int r; /* 行 ( row ) */
int c; /* 列 ( colomun ) */
for ( r = 0; r < DIMENSION; r++ ) {
for ( c = 0; c < DIMENSION; c++ ) {
result.a[r][c] = a1.a[r][c] - a2.a[r][c];
}
}
return result;
}
/*
* Matrix2D mul_Matrix2D ( Matrix2D a1, Matrix2D a2 );
* 「行列」の積
*
* ( a b ) ( e f ) = ( a * e + b * g a * f + b * h )
* ( c d ) ( g h ) ( c * e + d * g c * f + d * h )
*/
Matrix2D mul_Matrix2D ( Matrix2D a1, Matrix2D a2 ) {
Matrix2D result; /* 計算結果 */
int r; /* 行 ( row ) */
int c; /* 列 ( colomun ) */
int i;
for ( r = 0; r < DIMENSION; r++ ) {
for ( c = 0; c < DIMENSION; c++ ) {
double products = 0.0; /* a1 の r 行と a2 の c 列の内積の結果 */
/* a1 の r 行と a2 の c 列の内積を計算する */
for ( i = 0; i < DIMENSION; i++ ) {
products = products + a1.a[r][i] * a2.a[i][c];
/*
A=(a_ij), B=(b_ij), C = (c_ij) = AB
c_ij = \sum_{k=1}^n b_ik c_kj
*/
}
result.a[r][c] = products;
}
}
return result;
}
/*
* print_result 演算結果を出力する
*/
void print_result ( Matrix2D a1, Matrix2D a2, char *operator, Matrix2D a ) {
printf ( "%s の計算\n", operator );
print_Matrix2D ( a1 );
printf ( " と、 \n" );
print_Matrix2D ( a2 );
printf ( " との、%s は \n", operator );
print_Matrix2D ( a );
printf ( " です。\n\n" );
}
/*
* main
*/
int main( int argc, char *argv[] )
{
/*
a1 = ( 1 2 )
( 3 -1 )
a2 = ( -3 1 )
( 1 -2 )
*/
Matrix2D a1 = make_Matrix2D ( 1.0, 2.0, 3.0, -1.0 );
Matrix2D a2 = make_Matrix2D ( -3.0, 1.0, 1.0, -2.0 );
/* 和の出力 */
print_result ( a1, a2, "和", add_Matrix2D ( a1, a2 ) );
/* 差の出力 */
print_result ( a1, a2, "差", sub_Matrix2D ( a1, a2 ) );
/* 積の出力 */
print_result ( a1, a2, "積", mul_Matrix2D ( a1, a2 ) );
return 0;
}
/*
* 課題 20211112-03
*
* 20211112 20211112-03-QQQQ.c
*
* 整数型の配列を作り、それに 5 個のデータを入力し
* その値を 5 倍にしたものと 2 分の 1 にした値を
* それぞれ、画面に出力するプログラムを作りなさい
*
* 入力 => 処理 => 出力
* 複数のデータをまとめて入力して、一括処理をし、まとめて出力する
* 入力した(複数.. 大量な)データを保存する場所が必要
* => 配列に、入力データを記録させる
* !! データの量が多いので繰り返しで処理したい
*/
#include <stdio.h>
/*
*
*/
#define DATA_SIZE 5 /* データのサイズ (個数) */
/*
*
*/
int main(int argc, char *argv[]) {
int array[DATA_SIZE]; /* サイズが DATA_SIZE の整数型の配列 array の宣言 */
int i; /* 添字変数 i を宣言 */
for ( i = 0; i < DATA_SIZE; i++ ) { /* 配列 array に数値を読み込む */
/* プロンプト */
printf ( "%d 番目の整数値を入力してください : ", i + 1 );
/* 配列へのデータ入力 */
scanf ( "%d", &array[i] );
}
/* 入力された個々の値を 5 倍した物を出力 */
for ( i = 0; i < DATA_SIZE; i++ ) {
printf ( "%d\n", array[i]*5 ); /* 5 倍 */
}
/* 入力された個々の値を 1/2 した物を出力 */
for ( i = 0; i < DATA_SIZE; i++ ) {
printf ( "%d\n", array[i]/2 ); /* 2 分の 1 */
/* 整数割り算になるので、小数点以下は切り捨て */
}
/* 入力したデータを、二度(以上..)参照しているので、
変数(配列)に、データを記録させ保持する必要がある */
return 0;
}
#include <stdio.h>
/*
二次元平面上の点を構造体を用いて表現する
*/
int main(int argc, char *argv[] ) {
struct {
double x; /* x, y タグ名 : 構造体を要素の名前 */
double y;
} P; /* 点 P を構造体を利用して定義 */
/*
P <-> (x,y)
構造体によって、新しいデータ構造が作れる
「データの組み合わせ」の情報しかない
=> 基本、(その新しいデータ型に対する)操作は、
ほんとんど、何も準備されていない
構造体の場合、準備されている操作
(タグ名を利用して) 要素のデータの操作
データ全体の代入が可能
*/
/*
P <- (1.0,-2.0)
# C++ だったら、新しいデータ型の定数を作れる
# P = Point(1.0,-2.0) のような事が可能
# C では、新しいデータ型の定数を作るしくみが提供されていない
# => 個々の要素単位で、定数を作り、それを代入する必要がある
*/
P.x = 1.0;
P.y = -2.0;
/*
出力や入力の機能も、同様に自分で作る必要がある
*/
/* 点 P の出力 */
printf ( "P(%f,%f)\n", P.x, P.y );
/*
実現の構造
代入
P := (1.0,-2.0) P.x := 1.0
^ P.y := -2.0
|
v
struct {
double x; P.x
double y; P.y
}
出力
printf ( P );
^ printf ( "(%f,%f)\n", P.x, P.y );
|
v
struct {
double x; P.x
double y; P.y
}
新しいデータ型は、
既存のデータ型を組み合わせて実現されているので、
新しいデータ型に対する操作は、
既存データ型の操作の組み合わせで実現
逆に
もし、新しいデータ型の作り方が、
既存のデータ型から作るのではなく、
新規にゼロから作る場合は、
その新しいデータ型を操作するプログラムを作る時に、
その実装方法(命令の組み合わせ)を考えるのが困難になる
例:
二次元平面上の格子点 ( x, y 座標がともに整数である点 )
素直なやりかた (x,y) : struct { int x; int y };
二次元上の点に順番に番号をつけて、
一つの整数値で、表す事も可能
=> 操作が大変になってしまう
|
| 4
| 2 5
| 1 3 6
+------------
二次元平面上に、番号をつけることにより、
一つの整数値で、「点」を表現する事ができる
cf.
一年生の数学入門 A で学んだ
「(集合の)濃度」
有理数(全体の集合)と自然数(全体の集合)の濃度が等しい
*/
return 0;
}
#include <stdio.h>
/*
二次元平面上の点を構造体を用いて表現する
*/
int main(int argc, char *argv[] ) {
struct point { /* 構造体名 point を指定 */
double x; /* x, y タグ名 : 構造体を要素の名前 */
double y;
} P; /* 点 P を構造体を利用して宣言 */
struct point Q; /* 点 Q を構造体 point を利用して宣言 */
/*
P <-> (x,y)
構造体によって、新しいデータ構造が作れる
「データの組み合わせ」の情報しかない
=> 基本、(その新しいデータ型に対する)操作は、
ほんとんど、何も準備されていない
構造体の場合、準備されている操作
(タグ名を利用して) 要素のデータの操作
データ全体の代入が可能
*/
/*
P <- (1.0,-2.0)
# C++ だったら、新しいデータ型の定数を作れる
# P = Point(1.0,-2.0) のような事が可能
# C では、新しいデータ型の定数を作るしくみが提供されていない
# => 個々の要素単位で、定数を作り、それを代入する必要がある
*/
P.x = 1.0;
P.y = -2.0;
/*
出力や入力の機能も、同様に自分で作る必要がある
*/
/* 点 P の出力 */
printf ( "P(%f,%f)\n", P.x, P.y );
/*
実現の構造
代入
P := (1.0,-2.0) P.x := 1.0
^ P.y := -2.0
|
v
struct {
double x; P.x
double y; P.y
}
出力
printf ( P );
^ printf ( "(%f,%f)\n", P.x, P.y );
|
v
struct {
double x; P.x
double y; P.y
}
新しいデータ型は、
既存のデータ型を組み合わせて実現されているので、
新しいデータ型に対する操作は、
既存データ型の操作の組み合わせで実現
逆に
もし、新しいデータ型の作り方が、
既存のデータ型から作るのではなく、
新規にゼロから作る場合は、
その新しいデータ型を操作するプログラムを作る時に、
その実装方法(命令の組み合わせ)を考えるのが困難になる
例:
二次元平面上の格子点 ( x, y 座標がともに整数である点 )
素直なやりかた (x,y) : struct { int x; int y };
二次元上の点に順番に番号をつけて、
一つの整数値で、表す事も可能
=> 操作が大変になってしまう
|
| 4
| 2 5
| 1 3 6
+------------
二次元平面上に、番号をつけることにより、
一つの整数値で、「点」を表現する事ができる
cf.
一年生の数学入門 A で学んだ
「(集合の)濃度」
有理数(全体の集合)と自然数(全体の集合)の濃度が等しい
*/
Q = P; /* (構造体の場合..) 代入は用意されている */
/* !! 最近の ANSI C 言語では.. ( K&R C では、できない.. ) */
/* 点 Q の出力 */
printf ( "Q(%f,%f)\n", Q.x, Q.y );
return 0;
}
#include <stdio.h>
/*
二次元平面上の点を構造体を用いて表現する
*/
typedef struct { /* 構造体名 point を指定 */
double x; /* x, y タグ名 : 構造体を要素の名前 */
double y;
} Point; /* 構造体を利用した新しい型 Point を定義 */
int main(int argc, char *argv[] ) {
Point P; /* 点 P を新しい型 Point 利用して宣言 */
Point Q; /* 点 Q を新しい型 Point 利用して宣言 */
/*
P <-> (x,y)
構造体によって、新しいデータ構造が作れる
「データの組み合わせ」の情報しかない
=> 基本、(その新しいデータ型に対する)操作は、
ほんとんど、何も準備されていない
構造体の場合、準備されている操作
(タグ名を利用して) 要素のデータの操作
データ全体の代入が可能
*/
/*
P <- (1.0,-2.0)
# C++ だったら、新しいデータ型の定数を作れる
# P = Point(1.0,-2.0) のような事が可能
# C では、新しいデータ型の定数を作るしくみが提供されていない
# => 個々の要素単位で、定数を作り、それを代入する必要がある
*/
P.x = 1.0;
P.y = -2.0;
/*
出力や入力の機能も、同様に自分で作る必要がある
*/
/* 点 P の出力 */
printf ( "P(%f,%f)\n", P.x, P.y );
/*
実現の構造
代入
P := (1.0,-2.0) P.x := 1.0
^ P.y := -2.0
|
v
struct {
double x; P.x
double y; P.y
}
出力
printf ( P );
^ printf ( "(%f,%f)\n", P.x, P.y );
|
v
struct {
double x; P.x
double y; P.y
}
新しいデータ型は、
既存のデータ型を組み合わせて実現されているので、
新しいデータ型に対する操作は、
既存データ型の操作の組み合わせで実現
逆に
もし、新しいデータ型の作り方が、
既存のデータ型から作るのではなく、
新規にゼロから作る場合は、
その新しいデータ型を操作するプログラムを作る時に、
その実装方法(命令の組み合わせ)を考えるのが困難になる
例:
二次元平面上の格子点 ( x, y 座標がともに整数である点 )
素直なやりかた (x,y) : struct { int x; int y };
二次元上の点に順番に番号をつけて、
一つの整数値で、表す事も可能
=> 操作が大変になってしまう
|
| 4
| 2 5
| 1 3 6
+------------
二次元平面上に、番号をつけることにより、
一つの整数値で、「点」を表現する事ができる
cf.
一年生の数学入門 A で学んだ
「(集合の)濃度」
有理数(全体の集合)と自然数(全体の集合)の濃度が等しい
*/
Q = P; /* (構造体の場合..) 代入は用意されている */
/* !! 最近の ANSI C 言語では.. ( K&R C では、できない.. ) */
/* 点 Q の出力 */
printf ( "Q(%f,%f)\n", Q.x, Q.y );
return 0;
}
#include <stdio.h>
int main(int argc, char *argv[]) {
int a[3]; /* サイズ 3 の整数の要素を持つ配列の宣言 */
/*
=> a[0], a[1], a[2] の三つの変数の宣言と同様な効果
cf.
struct {
int a0;
int a1:
int a2:
} v;
=> v.a0, v.a1, v.a2 の三通つの宣言と同様
=>
三つの変数は別々に扱う事ができる
=> 「まとめて操作する」事が可能
例: 構造体の場合は、代入の時に、全体をまとめて操作できる
*/
/*
配列の要素は、「添え字」 ( 配列名の後ろに書く [] の中身 )
を利用して、指定が可能だが、
そこに、「整数の式(変数)」を利用する事が可能
cf.
構造体の場合は、要素を指定する場合、
タグ名を指定する必要がある ( 定「数」)
=> 構造体の要素の参照対象は、
プログラミング時に確定している
=>
配列の要素を指定する場合は、
その対象が、実行時にならないと決まらない場合がある
<= 添え字に変数が含まれていると、
その値が実行時にしか定まらないから..
=> 繰り返しと相性が良い
*/
/*
ベクトル 1
a := ( 2 )
3
*/
int i; /* 配列 a の要素を指定する変数 */
a[0] = 1;
a[1] = 2;
a[2] = 3;
/* 出力 */
printf ( " %d\n", a[0] );
printf ( "(%d)\n", a[1] );
printf ( " %d\n", a[2] );
/* 入力 */
printf ( "a の要素を三つ入力してください\n" );
/*
scanf ( "%d", &a[0] );
scanf ( "%d", &a[1] );
scanf ( "%d", &a[2] );
三つの命令がよくにている ( 添え字が異なるだけ )
=> 簡略可能では ?
!! 命令が似ている理由
!! メンバーが同等
!! => メンバーの型が同一(配列で表現できる)
似ている場合は、違う部分に変数を当てはめる事により、
同一にできる ( 前期に、「引数付き関数の導入」で、同じ議論 )
i=0;
scanf ( "%d", &a[i] );
i=1;
scanf ( "%d", &a[i] );
i=2;
scanf ( "%d", &a[i] );
i=0;
scanf ( "%d", &a[i] );
i++: i=1 => (i==0なので..) i = i + 1 ( i++ )
scanf ( "%d", &a[i] );
i++;
scanf ( "%d", &a[i] );
くり返しするために、最後に余分な命令ついかして
i=0;
scanf ( "%d", &a[i] );
i++: i=1 => (i==0なので..) i = i + 1 ( i++ )
scanf ( "%d", &a[i] );
i++;
scanf ( "%d", &a[i] );
i++;
<= 同じ命令が並ぶ
=> 繰り返し(while)にできる
i = 0;
while ( i < 3 ) {
scanf ( "%d", &a[i] );
i++;
}
=> 添え字変数 i の操作を一か所にまとめて記述する
for ( i=0; i < 3; i++ ) {
scanf ( "%d", &a[i] );
}
配列の操作は、for 構文と、非常に相性が良い
!! 配列を簡便に操作するために for 構文を作ったのでは ??
*/
for ( i=0; i < 3; i++ ) {
scanf ( "%d", &a[i] );
}
/* 出力 */
printf ( " %d\n", a[0] );
printf ( "(%d)\n", a[1] );
printf ( " %d\n", a[2] );
return 0;
}
/*
6 の約数の集合
約数の個数は、あらかじめ、 4 こである事は
解っているものとする
*/
#include <stdio.h>
#define SIZE_OF_ARRAY 4 /* 配列のサイズを指定 */
/* #define A B => 以後、 A とかくと B に置き換えられる */
int main(int argc, char *argv[]) {
int a[SIZE_OF_ARRAY]; /* 6 の約数の集合を配列 a で表現 */
int i; /* 配列を操作する添え字変数 */
int n;
/* 要素をいれてみる */
/* 6 の約数は 1, 2, 3, 6 であるが、あえて、具体的なものは指定 */
/*
候補をすべてしらべて、
条件が成立した場合に、その候補を記録する
*/
i = 0;
for ( n = 1; n <= 6; n++ ) {
/* n は、6 の約数候補を表す ( n = 1 ? 6 ) */
if ( 6 % n == 0 ) { /* n が 6 の約数の時成立 */
a[i] = n; /* 配列に n を入れる */
i++; /* 次の場所として i を増やす */
}
}
/* 6 の約数の集合を表示 */
printf ( "{ " );
for ( i = 0; i < SIZE_OF_ARRAY; i++ ) {
if ( i < SIZE_OF_ARRAY - 1 ) {
printf ( "%d, ", a[i] );
} else {
printf ( "%d ", a[i] );
}
}
printf ( "}\n" );
return 0;
}
/*
6 の約数の集合
約数の個数は、あらかじめ、 4 こである事は
解っているものとする
*/
#include <stdio.h>
#define SIZE_OF_ARRAY 4 /* 配列のサイズを指定 */
/* #define A B => 以後、 A とかくと B に置き換えられる */
int main(int argc, char *argv[]) {
int a[SIZE_OF_ARRAY]; /* 6 の約数の集合を配列 a で表現 */
int i; /* 配列を操作する添え字変数 */
int n;
/* 要素をいれてみる */
/* 6 の約数は 1, 2, 3, 6 であるが、あえて、具体的なものは指定 */
/* まず、条件を満たすものを探し、
配列に保存した後、次の条件を満たすものを探す
*/
n = 1; /* 最初答えは 1 */
for ( i = 0; i < SIZE_OF_ARRAY; i++ ) {
a[i] = n;
n++;
/* 次の候補 ( 「6 % n == 0」となるもの ) */
/* 最後の候補が見つかった後は、
その次がない
次がない場合も止まる ( 「n <= 6」を追加 )
*/
while ( 6 % n != 0 && n <= 6 ) {
/*
繰り返す条件は、
n が約数でなく、かつ n が 6 以下
*/
n++;
}
}
/* 6 の約数の集合を表示 */
printf ( "{ " );
for ( i = 0; i < SIZE_OF_ARRAY; i++ ) {
if ( i < SIZE_OF_ARRAY - 1 ) {
printf ( "%d, ", a[i] );
} else {
printf ( "%d ", a[i] );
}
}
printf ( "}\n" );
return 0;
}
/*
6 の約数の集合
約数の個数は、あらかじめ、 4 こである事は
解っているものとする
*/
#include <stdio.h>
#define SIZE_OF_ARRAY 4 /* 配列のサイズを指定 */
/* #define A B => 以後、 A とかくと B に置き換えられる */
int main(int argc, char *argv[]) {
int a[SIZE_OF_ARRAY]; /* 6 の約数の集合を配列 a で表現 */
int i; /* 配列を操作する添え字変数 */
int n;
int sum; /* 要素の総和を保持する変数 */
/* 要素をいれてみる */
/* 6 の約数は 1, 2, 3, 6 であるが、あえて、具体的なものは指定 */
/*
候補をすべてしらべて、
条件が成立した場合に、その候補を記録する
*/
i = 0;
for ( n = 1; n <= 6; n++ ) {
/* n は、6 の約数候補を表す ( n = 1 ? 6 ) */
if ( 6 % n == 0 ) { /* n が 6 の約数の時成立 */
a[i] = n; /* 配列に n を入れる */
i++; /* 次の場所として i を増やす */
}
}
/* 6 の約数の集合を表示 */
printf ( "{ " );
for ( i = 0; i < SIZE_OF_ARRAY; i++ ) {
if ( i < SIZE_OF_ARRAY - 1 ) {
printf ( "%d, ", a[i] );
} else {
printf ( "%d ", a[i] );
}
}
printf ( "}\n" );
/* すべての要素を 2 倍にしてみる */
for ( i = 0; i < SIZE_OF_ARRAY; i++ ) { /* 要素全部への処理 */
/* 個々の要素への処理 */
a[i] = a[i] * 2; /* 個々の要素を二倍する */
/* for 構文により、全ての要素を二倍する */
}
/* 2 倍した結果の表示 */
printf ( "{ " );
for ( i = 0; i < SIZE_OF_ARRAY; i++ ) {
if ( i < SIZE_OF_ARRAY - 1 ) {
printf ( "%d, ", a[i] );
} else {
printf ( "%d ", a[i] );
}
}
printf ( "}\n" );
/* a の中に、6 があるかどうか */
for ( i = 0; i < SIZE_OF_ARRAY; i++ ) {
if ( a[i] == 6 ) {
printf ( "a の %d 番目に 6 が含まれています\n", i );
}
}
/* 配列の要素を集計する (統計操作) */
sum = 0; /* 変数 sum には、配列a の全て要素の総和がはいる */
/* sum := a[0] + a[1] + a[2] + a[3] */
/* := 0 + a[0] + a[1] + a[2] + a[3] */
/* := ((((0 + a[0]) + a[1]) + a[2]) + a[3]) */
/*
=>
sum := 0 sum := 0
sum := sum + a[0] sum := 0 + a[0]
sum := sum + a[1] sum := (0+a[0])+a[1]
sum := sum + a[2] sum := ((0+a[0])+a[1])+a[2]
sum := sum + a[3] sum := (((0+a[0])+a[1])+a[2])+a[3]
=>
sum := 0
i=0;
sum := sum + a[i]
i=1;
sum := sum + a[i]
i=2;
sum := sum + a[i]
i=3;
sum := sum + a[i]
=>
sum := 0
i=0;
sum := sum + a[i]
i++;
sum := sum + a[i]
i++;
sum := sum + a[i]
i++;
sum := sum + a[i]
=>
sum := 0
i=0;
sum := sum + a[i]
i++;
sum := sum + a[i]
i++;
sum := sum + a[i]
i++;
sum := sum + a[i]
i++;
=>
sum := 0
i=0;
while ( i < 4 ) {
sum := sum + a[i]
i++;
}
=>
sum := 0
for ( i = 0; i < 4; i++ ) {
sum := sum + a[i]
}
*/
for ( i = 0; i < SIZE_OF_ARRAY; i++ ) {
sum = sum + a[i];
}
printf ( "a の要素の総和は %d になります\n", sum );
return 0;
}
2021/11/19
前回の内容
前回の内容 : データ構造 (2)
データ構造
機能 : 既存のデータ型から新しいデータ型を作る仕組み
目的 : データ(計算機内部の数値)を利用して、情報(現実の何かに対応するもの)を表現したい
表現方法 => コーディング ( データ <-> 情報 : 1 対 1 なら良い )
例: { 英数字記号 } ( : ASCII [文字] 集合 ) <-> { 小さな整数 ( 0 ? 255 ) }
情報(が表す対象..)が単純(構造を持たない..)な場合は、
適当な数値の集合で、対応関係 ( 1 対 1 ) があればよい
情報が構造を持つ場合 ( 例 : 二次元平面上の「点」は、x, y 座標からなる )
「構造を持つ」=> 他の情報の組み合わせでその情報が作られている
=> 対応するデータも構造をもっていた方が(対応付け[や、それを扱うプログラム]が簡単になる)
=> 「データ構造」が必要になる
(数学) 集合が構造を持つと、
その構造に基づく操作が可能になり、
それが、集合の性質にかかわってくる
C 言語で、利用可能な「データ構造」(の表現)
構造体
配列
共用体
ポインター型
構造体 : 複数のデータの組み合せ ( データタイプの直積 ) を作る
例: 2 次元平面上の「点」
その「点」に対応する座標の組 ( x 座標, y 座標 ) で表す事ができる
情報の世界 データの世界(C言語)
点 P struct {
^ double x;
| P=(x,y) double y;
v }
x 座標 x ----> double
x x
y 座標 y ----> double
構文 : struct { データの組み合せ } ( 要素の型名とタグ名を宣言 )
![めも]
! struct 構造体名 { データの組み合わせ }
! として、構造体に名前をつける事ができる
! => こうすると、(以後)
! 「struct 構造体名」だけで、
! 型を表現する事が可能になる
利用 : 「typedef struct { データの組み合せ } 型名」で、新しい型を作る
要素の参照 : タグ名を指定して要素が参照できる
配列 : 複数の『同じ型』の変数(配列の要素)をまとめたもの
同じ型の値が並んだもの(ベクトル)を表現するデータ型
配列の宣言 : 配列を構成する要素数を指定して宣言
要素の個数 ( 配列のサイズ )
要素の型
例 (整数を要素とするサイズ 3 の配列の宣言)
int a[3] -> 3 つの変数 ( a[0], a[1], a[2] : 配列 a の要素 ) を宣言
配列の要素(配列の一部となる変数)は、[] (添字) で参照可能
例 : a[1] -> 配列 a の 2 つ目 ( 1 つ目 a[0] なので.. ) を表す
「添字」には、「整数値を持つ式」が入れられる
配列と for 構文の関係
配列の要素を処理する場合は for 構文が馴染む
データ型 操作の構造
構造体 順接
例:
sturct { x, y, z } v
v.x = ..
v.y = ..
v.z = ..
配列 くり返し
例:
int v[3]
for ( i = 0; i < 3; i++ ) {
v[i] = ..
}
共用体 条件分岐
10:20 ? 10:30 休憩
配列が表現(しやすい)するデータ構造
(配列は、同じ型の要素の組み合わせ)
=> 同じ要素からなる情報を表現する
例 : 有限部分集合 : 集合の要素をいつか集めたもの
6 の約数の集合 = { 1, 2, 3, 6 }
自然数(全体)の集合の部分集合
C 言語での表現
int a[4]:
a[0] = 1;
a[1] = 2:
a[2] = 3;
a[3] = 6;
集合の要素に対する操作
=> for 構文で実装する事になる
例:
全ての要素を 2 倍
その集合の中に、ある自然数が入っているかどうか
配列使い方(その一)
同じ種類がまとまっている物
-> 集合を表現している
「集合」を表現する場合は、配列の方が(構造体より)良い
「集合の操作」は「要素の操作の繰返し」になる事が多い
「繰返し」と「配列」は相性がよい ( for 文 )
配列使い方(そのニ)
「集合」から、「集計」を行う
全体の情報を集約して一つのデータ書き換える作業
例 : 総和、平均、最大値、最小値..(検索[包含関係])
多次元の話
# 構造体のところ
# 既存の型(異なってもよい)を組み合わせて、新しい型を作る
# => 構造体の要素は、型をもてば、型は何でもよい
# => メンバの型も、構造体にしてよい (構造体の入れ子)
# # 構造体の要素に配列をいれることも(当然)できる
配列は、同じ型の並び、
=> 配列の配列を考える事もできる
多次元配列 ( 1 次元の配列は、単純な配列とよぶ )
多次元の配列
配列の配列が作れる : 多次元配列
[例]
int d[3][4]; /* 二次元 3 × 4 の 12 個の要素を持つ配列 */
cf.
一次元の配列は、ベクトルに対応
二次元の配列は、行列に対応
(n 次元の配列は、n 次元テンソルになる)
次元は幾つでも増やす事ができる
int t[3][4][5]; /* 三次元配列 */
まとめ
配列の処理の方法
for 構文をうまく利用する
配列 <-> リレーショナル DB (表型の DB)
<-> MS-Excel のデータ (表形式)
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20211119-01.c
/*
* 課題 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 ) {
double sum = 0.0; /* 総和は最初は 0 */
int i; /* 配列の要素を参照する添字変数 */
for ( i = 0; i < size; i++ ) { /* i = 0 〜 sum - 1 の間.. */
/*
** この部分を完成させなさい
*/
/* 「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 );
/*
** この部分を完成させなさい
*/
}
sum = dsum ( data, ARY_SIZE );
printf ( "入力されたデータの総和は %f です。\n", sum );
return 0;
}
2.3 9.1 5.9 2.7 3.2
$ ./20211119-01-QQQQ.exe 5 個のデータを入力します。 1 番目の数値を入力してください : 2.300000 2 番目の数値を入力してください : 9.100000 3 番目の数値を入力してください : 5.900000 4 番目の数値を入力してください : 2.700000 5 番目の数値を入力してください : 3.200000 入力されたデータの総和は 23.200000 です。 $
Download : 20211119-02.c
/*
* 課題 20211119-02
*
* 20211119 20211119-02-QQQQ.c
*
* 文字列の途中に文字を挿入する
*
* 利用方法
* コンパイル
* cc -o BASENAME.exe 20211119-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| ? | ? | ? | ? |
*/
int i;
int l;
printf ( "最初の cary = %s\n", cary );
/*
文字列 "abcde" の入った文字配列 cary の
3 文字目 ('c') と 4 文字目 'd' の間に、一文字 'X' を入れる
*/
/* 文字列の長さを求める */
/*
** この部分を完成させなさい
*/
/* cary の中の文字列の長さは、変数 l に入る */
for ( i = l; 3 <= i; 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;
}
123 987 456
$ ./20211119-02-QQQQ.exe 最初の cary = abcde 'X' を挿入した結果 : abcXde $
Download : 20211119-03.c
/*
* 20211119-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 ) ) { /* 小文字だった.. */
/*
** この部分を完成させなさい
*/
} else { /* そうでないなら */
return ch; /* そのまま返す */
}
}
/*
* main
*/
#define EOS '\0' /* EOS を定義 */
#define LINE_SIZE 128 /* 入力するのに十分に大きなサイズにする */
int main ( void ) {
char line[LINE_SIZE];
int i;
printf ( "小文字を含んだ文字列を入力してください : " );
/*
** この部分を完成させなさい
*/
for ( i = 0; line[i] != EOS; i++ ) {
line[i] = toupper ( line[i] ); /* 小文字を大文字に変換 */
}
printf ( "結果 : %s", line );
return 0;
}
aBcd123[]
$ ./20211119-03-QQQQ.exe 小文字を含んだ文字列を入力してください : 結果 : ABCD123[] $