Download : sample-001.c
/* * 2019/12/06 sample-001.c * * ポインター型変数の利用 * */ #include <stdio.h> #include <malloc.h> /* * 利用方法 * コンパイル * cc -o sample-001.exe sample-001.c * 実行 * ./sample-001.exe */ /* * main 関数 */ int main ( int argc, char *argv[] ) { int v; /* 整数型の変数を確保 */ int *p = &v; /* ポインター型変数 p に v のポインター値を代入する */ /* *p は、変数 v と全く同じに振る舞う */ *p = 1; printf ( "*p = %d\n", *p ); printf ( "v = %d\n", v ); *p = *p + 10; printf ( "*p = %d\n", *p ); printf ( "v = %d\n", v ); return 0; }
$ ./sample-001.exe *p = 1 v = 1 *p = 11 v = 11 $
Download : sample-002.c
/* * 2019/12/06 sample-002.c * * 動的領域の確保 (単純変数) * */ #include <stdio.h> #include <malloc.h> /* calloc/free を利用する場合に必要 */ /* * 利用方法 * コンパイル * cc -o sample-002.exe sample-002.c * 実行 * ./sample-002.exe */ /* * main 関数 */ int main ( int argc, char *argv[] ) { int *p; /* 整数型変数の領域を 1 つ分確保 */ p = (int *)calloc ( 1, sizeof(int) ); if ( p == NULL ) { /* メモリの確保に失敗した場合は NULL が返る */ printf ( "整数領域のメモリ確保に失敗しました。\n" ); } else { /* 以下は、*p を普通の整数型変数と同じ様に利用できる */ *p = 1; printf ( "*p = %d\n", *p ); *p = *p + 10; printf ( "*p = %d\n", *p ); /* 動的に確保したメモリは最後に必ず、free で解放する */ free ( p ); } return 0; }
$ ./sample-002.exe *p = 1 *p = 11 $
Download : sample-003.c
/* * 2019/12/06 sample-003.c * * ポインター型変数の利用(2) * */ #include <stdio.h> /* * 利用方法 * コンパイル * cc -o sample-003.exe sample-003.c * 実行 * ./sample-003.exe */ /* * main 関数 */ int main ( int argc, char *argv[] ) { int a[10]; /* 整数型の配列を確保 */ int *p = a; /* ポインター型変数 p に a の先頭の要素のポインター値を代入する */ /* p は、配列名 a と全く同じに振る舞う */ p[2] = 1; printf ( "p[2] = %d\n", p[2] ); printf ( "a[2] = %d\n", a[2] ); p[4] = p[2] + 10; printf ( "p[4] = %d\n", p[4] ); printf ( "a[4] = %d\n", a[4] ); return 0; }
$ ./sample-003.exe p[2] = 1 a[2] = 1 p[4] = 11 a[4] = 11 $
Download : sample-004.c
/* * 2019/12/06 sample-004.c * * 動的領域の確保 (配列) * */ #include <stdio.h> #include <malloc.h> /* * 利用方法 * コンパイル * cc -o sample-004.exe sample-004.c * 実行 * ./sample-004.exe */ /* * main 関数 */ int main ( int argc, char *argv[] ) { int *p; /* 整数型変数の領域を 10 つ分確保 */ p = (int *)calloc ( 10, sizeof(int) ); if ( p == NULL ) { /* メモリの確保に失敗した場合は NULL が返る */ printf ( "整数領域のメモリ確保に失敗しました。\n" ); } else { /* 以下は、p を普通の整数型配列名と同じ様に利用できる */ p[2] = 1; printf ( "p[2] = %d\n", p[2] ); p[4] = p[2] + 10; printf ( "p[4] = %d\n", p[4] ); /* 動的に確保したメモリは最後に必ず、free で解放する */ free ( p ); } return 0; }
$ ./sample-004.exe p[2] = 1 p[4] = 11 $
Download : sample-005.c
/* * 2019/12/06 sample-005.c * * 不定長の入力 (最大値が存在) * */ #include <stdio.h> /* * 利用方法 * コンパイル * cc -o sample-005.exe sample-005.c * 実行 * ./sample-005.exe */ #define MAX_OF_INPUT_SIZE 10 /* 入力できるデータ数 */ /* * main 関数 */ int main ( int argc, char *argv[] ) { int array[MAX_OF_INPUT_SIZE]; /* 整数型の配列を確保 */ int n; /* 入力される整数値の個数 */ int i; printf ( "データ数を入力してください : " ); scanf ( "%d", &n ); if ( ( 0 <= n ) && ( n < MAX_OF_INPUT_SIZE ) ) { for ( i = 0; i < n; i++ ) { printf ( "%d 番目の数値を入力してください : ", i + 1 ); scanf ( "%d", &array[i] ); } printf ( "入力された内容は以下の通りです。\n" ); for ( i = 0; i < n; i++ ) { printf ( "%d 番目の数値は %d です。\n", i + 1, array[i] ); } } else { printf ( "データ数(%d)が異常です。\n", n ); } return 0; }
5 453 32 -239 0 294
$ ./sample-005.exe < sample-005.in データ数を入力してください : 5 1 番目の数値を入力してください : 453 2 番目の数値を入力してください : 32 3 番目の数値を入力してください : -239 4 番目の数値を入力してください : 0 5 番目の数値を入力してください : 294 入力された内容は以下の通りです。 1 番目の数値は 453 です。 2 番目の数値は 32 です。 3 番目の数値は -239 です。 4 番目の数値は 0 です。 5 番目の数値は 294 です。 $
Download : sample-006.c
/* * 2019/12/06 sample-006.c * * 不定長の入力 (動的に領域を確保) * */ #include <stdio.h> #include <malloc.h> /* * 利用方法 * コンパイル * cc -o sample-006.exe sample-006.c * 実行 * ./sample-006.exe */ /* * main 関数 */ int main ( int argc, char *argv[] ) { int *parray; /* 整数型の配列の先頭 */ int n; /* 入力される整数値の個数 */ int i; printf ( "データ数を入力してください : " ); scanf ( "%d", &n ); if ( 0 <= n ) { if ( ( parray = (int *)calloc( n, sizeof(int) ) ) != NULL ) { for ( i = 0; i < n; i++ ) { printf ( "%d 番目の数値を入力してください : ", i + 1 ); scanf ( "%d", &parray[i] ); } printf ( "入力された内容は以下の通りです。\n" ); for ( i = 0; i < n; i++ ) { printf ( "%d 番目の数値は %d です。\n", i + 1, parray[i] ); } free ( parray ); } else { printf ( "整数領域のメモリ確保に失敗しました。\n" ); } } else { printf ( "データ数(%d)が異常です。\n", n ); } return 0; }
15 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
$ ./sample-006.exe < sample-006.in データ数を入力してください : 15 1 番目の数値を入力してください : 1 2 番目の数値を入力してください : 2 3 番目の数値を入力してください : 3 4 番目の数値を入力してください : 4 5 番目の数値を入力してください : 5 6 番目の数値を入力してください : 6 7 番目の数値を入力してください : 7 8 番目の数値を入力してください : 8 9 番目の数値を入力してください : 9 10 番目の数値を入力してください : 0 11 番目の数値を入力してください : 1 12 番目の数値を入力してください : 2 13 番目の数値を入力してください : 3 14 番目の数値を入力してください : 4 15 番目の数値を入力してください : 5 入力された内容は以下の通りです。 1 番目の数値は 1 です。 2 番目の数値は 2 です。 3 番目の数値は 3 です。 4 番目の数値は 4 です。 5 番目の数値は 5 です。 6 番目の数値は 6 です。 7 番目の数値は 7 です。 8 番目の数値は 8 です。 9 番目の数値は 9 です。 10 番目の数値は 0 です。 11 番目の数値は 1 です。 12 番目の数値は 2 です。 13 番目の数値は 3 です。 14 番目の数値は 4 です。 15 番目の数値は 5 です。 $
/* * DATE-02-QQQQ.c * * 動的なメモリの確保 * キーボードより正の整数を幾つか入力して、その要素が入った配列を返す * 0 以下の整数が入力されたら、終了とする * 配列のサイズは、正の整数の個数 + 1 とし、最後の要素には 0 を入れる */ /* * 利用方法 * コンパイル * cc -o BASENAME.exe FILENAME * 実行 * ./BASENAME.exe */ #include <stdio.h> #include <malloc.h> /* calloc/free を利用するので必要 */ /* 入力される整数値の個数は、予めて知る事ができないので、 動的領域確保を利用して、その領域を、入力時に決めて、確報する */ /* * read_n_integers * 正の整数値を入力し、その結果を収めた配列(先頭領域)へのポインタ値を返す * => 引数は、「これまで入力された整数の個数」を与える * 一番最初は * read_n_integer(0) として呼び出す * この関数呼び出された直後に負の整数が入力されたら * size + 1 の領域を確保すればよい */ int *read_n_integers( int size ) { int num; /* キーボードから入力された数値を保存する */ int *value; /* 確保された配列の先頭要素へのポインター */ printf ( "正の整数値を入力してください(0 以下だと入力を終了します):" ); scanf ( "%d", &num ); if ( num <= 0 ) { /* 入力が全部終ったので、配列を作成する */ /* 配列のサイズは、引数で指定された個数 + 1 となる */ if ( ( value = (int *)calloc ( size + 1, sizeof ( int ) ) ) != NULL ) { /* 動的メモリは取り出せるとは限らないので、結果をチェック */ /* value = malloc( (size+1)*sizeof(int) ); */ /* 「代入」は、「代入式」として扱われ、その値は、代入演算子の右辺の値 */ /* a=b=1; -> a=(b=1) -> b=1; a=1 */ /* calloc( a, b ) <-> malloc( a * b ) */ /* 変数の境界をそろえる[割り切れる数]にする */ value[ size ] = 0; /* 最後の要素として 0 を代入 */ } /* else {} */ /* NULL が帰った場合は、そのまま、値として返す */ } else { /* 入力が終っていないので、更に、値を読むために再帰呼び出し */ if ( ( value = read_n_integers( size + 1 ) ) != NULL ) { /* 結果が NULL でなければ、配列が作られている */ /* size 番目の要素を配列に記録 */ value[size] = num; /* 値をしっぽの方からいれてゆく */ } /* else {} */ /* NULL が帰った場合は、そのまま、値として返す */ } /* いずれの場合でも value を返す */ /* value が NULL の時と、そうでない時があるが、 いずれにせよ、その値を返す value が NULL という事は、実は、メモリが確保できなかった事を意味するので そのばで、終了してもよいが、 再帰の場合は、異常値を返す形で、最後まで実行を継続する事が望ましい */ return value; } /* * main */ int main ( int argc, char *argv[] ) { int *array; /* n 個数の要素をもつ配列の先頭をもつ */ int i; /* read_n_integers を呼び出して、n 個の整数値を入力する */ /* 引数には、入力済のデータ数を指定するので、最初は 0 を指定する */ if ( ( array = read_n_integers( 0 ) ) != NULL ) { /* read_n_integers は、NULL を返す可能性がある */ /* 入力された要素を画面に出力 */ for ( i = 0; array[i] > 0; i++ ) { printf ( "%d th data = %d\n", i, array[i] ); } /* malloc/calloc で確保したメモリは、必ず free で解放する */ free ( array ); /* 確保された領域を解放する */ } /* else {} */ /* NULL の場合はエラーなので、何もしない */ return 0; }
#include <stdio.h> /* sizeof 演算子は、引数の型(や対象[値]の型)の メモリ上で占めるサイズを整数値に置き換える !! sizeof は「(C 言語の)関数」ではない */ int main(int argc, char *argv[]) { printf ( "sizeof(char) = %d\n", sizeof( char ) ); /* char 型のメモリ上のサイズ */ /* メモリセルの個数 */ /* byte 数を表す */ printf ( "sizeof(int) = %d\n", sizeof( int ) ); printf ( "sizeof(double) = %d\n", sizeof( double ) ); return 0; }
#include <stdio.h> /* 配列の要素の番地を知りたい */ int main(int argc, char *argv[]) { char ca[10]; int ia[10]; double da[10]; printf ( "ca = %p, &ca[0] = %p, &ca[1] = %p, &ca[3] = %p\n", ca, &ca[0], &ca[1], &ca[3] ); /* & は、その変数の値が記録されているセルの位置を含むポインター値を返す */ printf ( "ca = %p, ca+0 = %p, ca+1 = %p, ca+3 = %p\n", ca, ca+0, ca+1, ca + 3 ); /* ary[i] <-> *(ary+i); */ /* 「*」と「&」が逆演算 => &*ary <-> ary / *&v <-> v */ printf ( "ia = %p, &ia[0] = %p, &ia[1] = %p, &ia[3] = %p\n", ia, &ia[0], &ia[1], &ia[3] ); printf ( "ia = %p, ia+0 = %p, ia+1 = %p, ia+3 = %p\n", ia, ia+0, ia+1, ia + 3 ); /* ia は「整数型」へのポインタ値 (「『整数』を指す」という情報を持っている*/ /* ia + 1 は、「(1 つ)次の整数を指す」必要がある */ /* => 番地番号としては、 +4 (整数サイズ) 増える */ printf ( "da = %p, &da[0] = %p, &da[1] = %p, &da[3] = %p\n", da, &da[0], &da[1], &da[3] ); printf ( "da = %p, da+0 = %p, da+1 = %p, da+3 = %p\n", da, da+0, da+1, da + 3 ); return 0; }
#include <stdio.h> int main(int argc, char *argv[]) { int a = 10; int b = 20; int c = 30; printf ( "&a = %p, &b = %p, &c = %p\n", &a, &b, &c ); printf ( "&a = %p, &b = %p, &a + 1 = %p\n", &a, &b, &a + 1 ); printf ( "a = %d, b = %d, *(&a + 1) = %d\n", a, b, *(&a + 1) ); /* 変数 a の情報だけを利用して、変数 b の値が取り出せる */ /* => 変数 a と変数 b がたまたま、隣り合った領域に割り当てられていいたから.. */ *(&a + 1) = 9999; /* b の値を 9999 に書き換えてしまっている */ printf ( "a = %d, b = %d, *(&a + 1) = %d\n", a, b, *(&a + 1) ); /* メモリモデルの立場からは、この振る舞いを説明する事ができる 単純に C 言語の立場から「見る」と、「変な事が起きている」ように見える */ /* 「おかしい事」を理解する必要はない 1. 「おかしい事が起きうる」事は「覚悟」していてほしい => ミスをした時に、そのミスの原因がよくわからない 2. 「おかしな事」も含め「便利な事」もできる => 「便利な使い方」だけ、きちんと学んでほしい */ return 0; }
#include <stdio.h> void sub ( int *pa ) { /* 「int *pa」 <-> (*pa) が整数型変数 pa は * を付けると整数型の変数ようなもの # a が変数で、&a が変数 a へのポインタ値 *(&a) <-> a => pa は 整数型へのポインター値を持つ変数 pa は「整数型へのポインター」になる pa は「整数型ポインター」になる [復習] ポインター値を値として記録する変数がポインター(変数) */ printf ( "pa = %p, *pa = %d\n", pa, *pa ); /* 変数 *pa の値(整数値)が表示される ポインター値 番地番号 => 実際に渡されるのは、こちらだけ 型情報 => 仮引数変数の型宣言で補われる # 変数の型宣言をチェックする事によって、 # 誤解が起きないようになっている ここでは、 pa が持つ値が、&a なので、 *pa -> *(&a) -> a -> a の値 */ *pa = 9999; /* 変数 a の値を 9999 に変更(代入) */ } int main(int argc, char *argv[]) { int a = 10; printf ( "a = %d, &a = %p\n", a, &a ); sub ( &a ); /* 「a へのポインタ値」が渡される */ /* 変数 a が割り当てられているメモリセルの先頭の番地番号と 型情報 => 本当に「(実行時点の..)値」となるのは、 「番地番号」のみ */ printf ( "a = %d, &a = %p\n", a, &a ); /* 関数 sub に、変数 a へのポインター値を (実引数して)与えたので、 変数 a の値を書き換えられてしまった => scanf は、この仕組みを利用して、 入寮した値を変数に代入していた */ return 0; }
#include <stdio.h> int main(int argc, char *argv[]) { int a; printf ( "&a = %p\n", &a ); /* 表示されるのは番地番号だけ */ printf ( "&a + 1 = %p\n", &a + 1 ); /* int 型へのポインタ値なので +4 (sizeof(int))だけ増える */ printf ( "(char *)&a = %p\n", (char *)&a ); /* キャスト「(char *)」によって、&aの値 (int 型へのポインタ値)が、 char 型へのポインタ値に変更される */ printf ( "&a + 1 = %p\n", ((char *)&a) + 1 ); /* char 型へのポインタ値なので +1 (sizeof(char))だけ増える */ return 0; }
#include <stdio.h> #include <malloc.h> /* 以下の動的領域確保のための malloc / free を利用する場合の宣言 */ int main(int argc, char *argv[]) { char *cp; /* char 型へのポインタ型変数 : 値は未定義 => 初期化 */ int i; cp = malloc( 10 ); /* 10 byte 分の領域を確保して、その先頭を指すポインター値が返る */ /* char ca[10]; 領域確保を、コンパイル時点で決めている cp = ca; */ if ( cp == NULL ) { /* 確保に失敗した場合は NULL 値が返る */ /* この条件が成立した場合は、確保できていないので、要素を参照してはいけない */ printf ( "十分が領域が確保できませんでした\n" ); } else { /* 領域が確保できたので、cp は、文字型配列の名前と同じように利用できる */ for ( i = 0; i < 10; i++ ) { cp[i] = i * i; } for ( i = 0; i < 10; i++ ) { printf ( "cp[%d]=%d\n", i, cp[i] ); } free ( cp ); /* 確保した領域を解放する <=> 配列とは異なる部分 */ /* 解法した後に、その領域の値を変更していけない */ /* cp[2] = 2; */ } }
前回(2019/12/06)の内容 メモリモデル(コンピュータの「生」のイメージ) メモリはセルの集まり : セルには 1 byte 分の情報を記録 セルには、セルの場所を表す「番地番号」が一意の連続した整数値がついている # 「番号番号」が整数値なので、「計算」が可能 セルの値の取り出しや設定(代入)は、「番地番号」を利用してセルを指定して行う C 言語の配列との比較 メモリは一つ : 配列は、複数 (先頭の場所を配列名、サイズは宣言で指定) セルのサイズは 1 byte : 配列は要素のサイズが色々(宣言型できまる) セルの指定は番地番号で行う : 配列は配列名と添字 (一般の変数は名前だけ) 「番地番号」=> 整数値 => 「値」を持つ / 計算ができる 「値」を持つ => 関数の引数に渡せる/関数の帰り値にする事ができる 計算ができる => 要素を、間接的に参照 => 関数の実引数に配列名を指定し、関数の中で配列要素の値が変更(代入)ができる理由(根拠/仕組み) 配列名 ary 対し ary[i] (要素の参照) <=> *(ary + i) # 「変数」: C 言語から見た(「生」でない、抽象化された)イメージ メモリと変数(普通の単純[配列の要素でない]変数)の関係 セルの(1 以上の..)並びが、変数 (変数の特質はセルの特質) char 型の場合 => 1 つのセル int 型の場合(32bit CPU であれば) => 4 つのセル double 型の場合 (64bit) => 8 つのセル # sizeof 演算子を利用して、セル数(byte 数)を得る事できる # # その処理系において # # => C 言語では、int 型のサイズは、処理系によって異なる # # !! 同じ PC でも、OS が違ったり、同じ OS でも違う会社の C Compiler だと異なるサイズになる可能性がある # # !!! なぜ、C 言語のサイズが違うか # # !!! => C 言語は、そのシステムで、最も効率(都合..)が良いサイスを選ぶ 「ポインター値」とは何か ? 基本は番地番号(実行時)だが、型属性も持つ(コンパイル時) 「番地番号」=> printf( "%p" ) 表示されるもの(整数値:16進数) 「型情報」も持っている 型情報 = メモリ上のセル(byte)サイズ(メモリへ処理) + 値に適用する演算 # セル数が利用される状況の例 # 代入 # char ch, dh; ch = dh: 1 byte コピー # int i, j; i = j; 4 byte コピー # 値に適用する演算の例 # int 型の割り算 : 10/3 # => 整数割り算なので、答えは 3 # double 型の割り算 : 10.0/3.0 # => 浮動小数点数割り算なので答えは 3.3333 => ポインタ値を操作する時にも、その型情報が利用される 例 : +1 とすると番地番号としては sizeof(型)だけ増える [今日の話] ポインター値とポインターの話 ポインター値 変数に & につけると得られる # 「変数」は、「メモリのセル」に対応づけられていて # その「メモリのセル」が「番地番号」を持っている # ポインター値の %p で表示される「値」は、その「番地番号」 # => 実行時に「値」して扱われるのは「型情報」が取り除かれた番地番号に対応 # # 「型」情報は、コンパイル時だけの情報で、実行時は失われている # # 「型」の情報は、「値」にではなく、「値」の使う側にある # 変数には型があるので # ポインター値には、その型の情報が引き継がれる # 型の情報は、コンパイル時は、保持されているが # その情報はデータから、そのデータの扱う側に移動されていて # データとしては、その情報は残らない ポインター値の操作方法 番地番号の変更 => 整数値の加算、減算が可能 int *pa; pa がポインター値をもっている場合 pa = pa + 1; 番地番号が変化 # sizeof(int) = 4 だけ増える # pa + 1 <-> &*( pa + 1 ) <-> & (pa[1]) <-> & pa[1] cf. double *pb; pb = pb + 1; 番地番号が変化 # sizeof(double) = 8 だけ増える 引き算も可能 int *pa; int *pc; pc = pa - 10; 番地が変化 # sizeof(int) * 10 = 40 だけ減る # pc <-> pa - 10 <-> &*( pa - 10 ) <-> & pa[-10] # pc[0] <-> pa[-10] # pc[10] <-> pa[0] # pc[10] <-> *(pc+10) <-> *( pa - 10 + 10 ) <-> pa[0] int pa[10]; /* pa[0] ? pa[9] */ int *pb = pa - 1; /* pb[1] ? pb[10] <-> *(pb+1) ? *(pb+10) <-> *(pa-1+1) ? *(pa-1+10) <-> *(pa+0)? *(pa+9) <-> pa[0] ? pa[9] */ ポインター同士の引き算は、整数値になる int ia[10]; int *pa = ia + 4; /* pa <- &ia[4] */ ini *pb = ia + 7; /* pb <- &ia[7] */ printf ( "%d\n", pb - pa ); /* 3 = ( 7 - 4 ) = pb - pa */ /* pb = pa + ( pb - pa ) */ # int *ip; # ip++; /* ip = ip + 1 => ip が指しているであろう配列要素の次の要素を指す */ 番地 型情報の変更 ポインター値の前に「(型名) : キャスト演算子」を付ける事により 型情報を変更する事ができる 動的領域 変数宣言によるメモリ確保は、コンパイル時に「確保量」が確定する。 動的領域確保 : 実行時に、好きなサイズで領域を確保する事ができる malloc(領域サイズ(byte 数))で、領域が確保され、その先頭の要素を指すポインター値がかえる => 非常に便利 確保できる保証はない 確保できなかった場合は、NULL 値が返るのでチェックが必要 確保できれば、そのまま、利用できる # 配列とは違い、名前がないので、ポインタ変数を用意して、 # その値を保持する必要がある # 確保した領域の参照は、このポインタ変数を経由して行う 確保した、領域は、free をつかって、開放する必要がある # 開放した後に、使ってしまう # (初期化問題)確保するまえに使ってしまう
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20191213-01.c
/* * 20190111-01-QQQQ.c * * 三角形の形をした配列 * */ /* * 利用方法 * コンパイル * cc -o BASENAME.exe FILENAME * 実行 * ./BASENAME.exe */ #include <stdio.h> #define ARRAY_SIZE_N 10 /* * * 0 a[0][0] * 1 a[1][0], a[1][1] * 3 a[2][0], a[2][1], a[2][2] * 6 .. * a[9][0], a[9][1], a[9][2], .., a[9][9] * */ int get_tri ( int *ary, int n, int m ) { /* ** この部分を完成させなさい */ } void set_tri ( int *ary, int n, int m, int value ) { /* ** この部分を完成させなさい */ } /* * main */ int main ( int argc, char *argv[] ) { int triary[ARRAY_SIZE_N*(ARRAY_SIZE_N+1)/2]; int n; int m; int i; for ( n = 0; n < ARRAY_SIZE_N; n++ ) { for ( m = 0; m <= n; m++ ) { set_tri ( triary, n, m, n * 100 + m ); } } for ( i = 0; i < ARRAY_SIZE_N*(ARRAY_SIZE_N+1)/2; i++ ) { printf ( "triary[%d] = %d\n", i, triary[i] ); } for ( n = 0; n < ARRAY_SIZE_N; n++ ) { for ( m = 0; m <= n; m++ ) { printf ( "triary[%d][%d] = %d\n", n, m, get_tri( triary, n, m ) ); } } return 0; }
$ ./20191213-01-QQQQ.exe triary[0] = 0 triary[1] = 100 triary[2] = 101 triary[3] = 200 triary[4] = 201 triary[5] = 202 triary[6] = 300 triary[7] = 301 triary[8] = 302 triary[9] = 303 triary[10] = 400 triary[11] = 401 triary[12] = 402 triary[13] = 403 triary[14] = 404 triary[15] = 500 triary[16] = 501 triary[17] = 502 triary[18] = 503 triary[19] = 504 triary[20] = 505 triary[21] = 600 triary[22] = 601 triary[23] = 602 triary[24] = 603 triary[25] = 604 triary[26] = 605 triary[27] = 606 triary[28] = 700 triary[29] = 701 triary[30] = 702 triary[31] = 703 triary[32] = 704 triary[33] = 705 triary[34] = 706 triary[35] = 707 triary[36] = 800 triary[37] = 801 triary[38] = 802 triary[39] = 803 triary[40] = 804 triary[41] = 805 triary[42] = 806 triary[43] = 807 triary[44] = 808 triary[45] = 900 triary[46] = 901 triary[47] = 902 triary[48] = 903 triary[49] = 904 triary[50] = 905 triary[51] = 906 triary[52] = 907 triary[53] = 908 triary[54] = 909 triary[0][0] = 0 triary[1][0] = 100 triary[1][1] = 101 triary[2][0] = 200 triary[2][1] = 201 triary[2][2] = 202 triary[3][0] = 300 triary[3][1] = 301 triary[3][2] = 302 triary[3][3] = 303 triary[4][0] = 400 triary[4][1] = 401 triary[4][2] = 402 triary[4][3] = 403 triary[4][4] = 404 triary[5][0] = 500 triary[5][1] = 501 triary[5][2] = 502 triary[5][3] = 503 triary[5][4] = 504 triary[5][5] = 505 triary[6][0] = 600 triary[6][1] = 601 triary[6][2] = 602 triary[6][3] = 603 triary[6][4] = 604 triary[6][5] = 605 triary[6][6] = 606 triary[7][0] = 700 triary[7][1] = 701 triary[7][2] = 702 triary[7][3] = 703 triary[7][4] = 704 triary[7][5] = 705 triary[7][6] = 706 triary[7][7] = 707 triary[8][0] = 800 triary[8][1] = 801 triary[8][2] = 802 triary[8][3] = 803 triary[8][4] = 804 triary[8][5] = 805 triary[8][6] = 806 triary[8][7] = 807 triary[8][8] = 808 triary[9][0] = 900 triary[9][1] = 901 triary[9][2] = 902 triary[9][3] = 903 triary[9][4] = 904 triary[9][5] = 905 triary[9][6] = 906 triary[9][7] = 907 triary[9][8] = 908 triary[9][9] = 909 $
Download : 20191213-02.c
/* * DATE-02-QQQQ.c * * 動的なメモリの確保 * キーボードより正の整数を幾つか入力して、その要素が入った配列を返す * 0 以下の整数が入力されたら、終了とする * 配列のサイズは、正の整数の個数 + 1 とし、最後の要素には 0 を入れる */ /* * 利用方法 * コンパイル * cc -o BASENAME.exe FILENAME * 実行 * ./BASENAME.exe */ #include <stdio.h> #include <malloc.h> /* calloc/free を利用するので必要 */ /* * read_n_integers */ int *read_n_integers( int size ) { int num; /* キーボードから入力された数値を保存する */ int *value; /* 確保された配列の先頭要素へのポインター */ printf ( "正の整数値を入力してください(0 以下だと入力を終了します):" ); scanf ( "%d", &num ); if ( num <= 0 ) { /* 入力が全部終ったので、配列を作成する */ /* 配列のサイズは、引数で指定された個数 + 1 となる */ if ( ( value = (int *)calloc ( size + 1, sizeof ( int ) ) ) != NULL ) { /* 動的メモリは取り出せるとは限らないので、結果をチェック */ value[ size ] = 0; /* 最後の要素として 0 を代入 */ } /* else {} */ /* NULL が帰った場合は、そのまま、値として返す */ } else { /* 入力が終っていないので、更に、値を読むために再帰呼び出し */ if ( ( value = read_n_integers( size + 1 ) ) != NULL ) { /* 結果が NULL でなければ、配列が作られている */ /* size 番目の要素を配列に記録 */ /* ** この部分を完成させなさい */ } /* else {} */ /* NULL が帰った場合は、そのまま、値として返す */ } /* いずれの場合でも value を返す */ /* ** この部分を完成させなさい */ } /* * main */ int main ( int argc, char *argv[] ) { int *array; /* n 個数の要素をもつ配列の先頭をもつ */ int i; /* read_n_integers を呼び出して、n 個の整数値を入力する */ /* 引数には、入力済のデータ数を指定するので、最初は 0 を指定する */ if ( ( array = read_n_integers( 0 ) ) != NULL ) { /* read_n_integers は、NULL を返す可能性がある */ /* 入力された要素を画面に出力 */ for ( i = 0; array[i] > 0; i++ ) { printf ( "%d th data = %d\n", i, array[i] ); } /* malloc/calloc で確保したメモリは、必ず free で解放する */ /* ** この部分を完成させなさい */ } /* else {} */ /* NULL の場合はエラーなので、何もしない */ return 0; }
12 34 5 6 90 -1
$ ./20191213-02-QQQQ.exe 正の整数値を入力してください(0 以下だと入力を終了します):12 正の整数値を入力してください(0 以下だと入力を終了します):34 正の整数値を入力してください(0 以下だと入力を終了します):5 正の整数値を入力してください(0 以下だと入力を終了します):6 正の整数値を入力してください(0 以下だと入力を終了します):90 正の整数値を入力してください(0 以下だと入力を終了します):-1 0 th data = 12 1 th data = 34 2 th data = 5 3 th data = 6 4 th data = 90 $