Download : sample-001.c
/* * 2018/12/21 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
/* * 2018/12/21 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
/* * 2018/12/21 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
/* * 2018/12/21 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
/* * 2018/12/21 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
/* * 2018/12/21 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 です。 $
#include <stdio.h> int main(int argc, char *argv[]) { int i; int j; int k; printf ( "&i = %p\n", &i ); /* %p は、アドレスを16進表示する */ printf ( "&j = %p\n", &j ); printf ( "&k = %p\n", &k ); return 0; }
#include <stdio.h> int main(int argc, char *argv[]) { int a[3]; printf ( "&a[0] = %p\n", &a[0] ); printf ( "&a[1] = %p\n", &a[1] ); printf ( "&a[2] = %p\n", &a[2] ); /* 「&」: アドレス演算子 => 変数の前につけることにより、変数に対応した メモリセルのアドレスを取り出す */ /* C 言語 メモリ a +-------+ ===== +---+ | a[0] | | | 4 つのセル(4byte) +-------+ ==* +---+ が一つ変数a[0] に対応 | a[1] | | | | => 次の a[1] は、4 つ先 +-------+ | +---+ | a[2] | | | | +-------+ | +---+ <- int -> *== | | 4byte +---+ 1byte */ return 0; }
#include <stdio.h> void sub ( int a, int b ) { printf ( "&a = %p\n", &a ); printf ( "&b = %p\n", &b ); printf ( "a = %d\n", a ); /* 仮引数変数 a には、呼び出し側の実引数の i の値「1」が コピーされているので、同じく 1 になる */ /* しかし、これは、たんに「値」がコピー(渡)されているだけ 「変数そのもの」が渡されているわけではない */ /* その証拠に、アドレス値が異なる */ } int main(int argc, char *argv[]) { int i = 1; int j = 2; printf ( "&i = %p\n", &i ); printf ( "&j = %p\n", &j ); sub ( i, j ); return 0; }
#include <stdio.h> void sub ( int a, int b ) { printf ( "&a = %p\n", &a ); printf ( "&b = %p\n", &b ); printf ( "a = %d\n", a ); } void sub2 ( int x, int y ) { printf ( "&x = %p\n", &x ); printf ( "&y = %p\n", &y ); printf ( "x = %d\n", x ); } int main(int argc, char *argv[]) { int i = 1; int j = 2; printf ( "&i = %p\n", &i ); printf ( "&j = %p\n", &j ); sub ( i, j ); sub2 ( i, j ); return 0; }
#include <stdio.h> void sub ( int a, int b ) { int c; printf ( "c = %d\n", c ); /* 変数 c は初期化していない => どんな値になるかは不明 */ printf ( "&a = %p\n", &a ); printf ( "&b = %p\n", &b ); printf ( "&b = %p\n", &c ); printf ( "a = %d\n", a ); c = 1234567; /* 変数に値を代入してみる .. */ } void sub2 ( int x, int y ) { int z; printf ( "z = %d\n", z ); /* 変数 z は初期化していない => どんな値になるかは不明なはず */ printf ( "&x = %p\n", &x ); printf ( "&y = %p\n", &y ); printf ( "&z = %p\n", &z ); printf ( "x = %d\n", x ); } int main(int argc, char *argv[]) { int i = 1; int j = 2; printf ( "&i = %p\n", &i ); printf ( "&j = %p\n", &j ); sub ( i, j ); sub2 ( i, j ); return 0; }
#include <stdio.h> /* sum(n) は、 n + (n-1) + ... + 2 + 1 = n(n+1)/2 */ int sum(int n) { printf ( "n = %d\n", n ); printf ( "&n = %p\n", &n ); if ( n == 0 ) { return 0; } else { return sum ( n - 1 ) + n; /* sum(10) = sum(10-1) + 10 */ /* sum(10-1) = sum(9) => sum(9) の計算では n が 9 になっている */ } } int main(int argc, char *argv[]) { printf ( "sum(10)=%d\n", sum(10) ); return 0; }
#include <stdio.h> int main(int argc, char *argv[] ) { char vc; int vi; double vd; printf ( "sizeof(vc) = %d\n", sizeof ( vc ) ); printf ( "sizeof(vi) = %d\n", sizeof ( vi ) ); printf ( "sizeof(vd) = %d\n", sizeof ( vd ) ); /* sizeof を利用して、変数が占めるメモリのサイズが得られる */ return 0; }
#include <stdio.h> int main(int argc, char *argv[] ) { char vc; int vi; double vd; printf ( "sizeof(vc) = %d\n", sizeof ( vc ) ); printf ( "sizeof(vi) = %d\n", sizeof ( vi ) ); printf ( "sizeof(vd) = %d\n", sizeof ( vd ) ); /* sizeof を利用して、変数が占めるメモリのサイズが得られる */ /* メモリモデルを意識したプログラムを作るため */ /* この値がシステムによって異なる */ printf ( "&vc = %p\n", &vc ); printf ( "&vi = %p\n", &vi ); printf ( "&vd = %p\n", &vd ); printf ( "&vc + 1 = %p\n", (&vc) + 1 ); printf ( "&vi + 1 = %p\n", (&vi) + 1 ); printf ( "&vd + 1 = %p\n", (&vd) + 1 ); /* それぞれ、アドレス値が、sizeof(型)だけ増えている それぞれの値が、型情報を持っている 具体的には、 &vc は(変数 vc が char 型なので..) (char *)型 &vi は(変数 vi が int 型なので..) (int *)型 などとなる 値だけででなく「型」をもっている */ return 0; }
#include <stdio.h> int main(int argc, char *argv[] ) { int vi; printf ( "sizeof(vi) = %d\n", sizeof ( vi ) ); printf ( "&vi = %p\n", &vi ); printf ( "&vi + 1 = %p\n", (&vi) + 1 ); /* この結果は、1 ではなく 4 (sizeof(int)) だけ アドレス値が変化 */ return 0; }
#include <stdio.h> int main(int argc, char *argv[] ) { int ai[2]; printf ( "sizeof(ai[0]) = %d\n", sizeof ( ai[0] ) ); printf ( "&ai[0] = %p\n", &ai[0] ); printf ( "&ai[0] + 1 = %p\n", (&ai[0]) + 1 ); return 0; }
#include <stdio.h> int main(int argc, char *argv[] ) { int ai[2]; printf ( "sizeof(ai[0]) = %d\n", sizeof ( ai[0] ) ); printf ( "&ai[0] = %p\n", &ai[0] ); /* &ai[0] => &(*(ai+0)) where ai[i] <=> *(ai+i) => &(*(ai)) => ai where * と & は逆演算なので、対消滅する ---> 配列名が、実は先頭の要素の「ポインタ値」になる */ printf ( "&ai[0] + 1 = %p\n", (&ai[0]) + 1 ); /* (&ai[0]) + 1 => ai + 1 => &*(ai + 1) => &(*(ai + 1)) => &(ai[1]) => ai[1] のポインタ値(アドレス値) 配列の次の要素のアドレスだから、サイズだけずれてないと困る */ return 0; }
/* ???????A(int *)?^??l???w???? => ?????\???A?h???X????????????e?? 1 ????? */ void set_one ( int *p ) { *p = 1; /* ??яo??????A&i ???w?????????A p == &i ???? *p == *(&i) == i ???? => ????d?g???p???? scanf ???????l???X??????? */ }
/* ???????A(char *)?^??l???w???? => ?????\???A?h???X????????????e?? 1 ????? */ void set_one ( char *p ) { /* p-012-1.c ??????A??????^???? */ /* p-012-1.c ???A(int *) ?^?????A???????A(char *)?^ */ *p = 1; /* 1000 = 768 + 43 = 256 * 3 + 32 int = 4 byte +-------+ +-------+ | 32 | Low | 1 | +-------+ +-------+ | 3 | | 0 | +-------+ +-------+ | 0 | | 0 | +-------+ +-------+ | 0 | Highg | 0 | +-------+ +-------+ p-012-1.c ??? char 1 byte 1000 1 769 +-------+ +-------+ +-------+ | 32 | Low | 1 | | 1 | +-------+ +-------+ +-------+ | 3 | | 3 | +-------+ +-------+ | 0 | | 0 | +-------+ +-------+ | 0 | Highg | 0 | +-------+ +-------+ p-012-2.c ??? */ }
#include <stdio.h> int main(int argc, char *argv[]) { int i; i = 1000; printf ( "i = %d\n", i ); set_one ( &i ); /* ??????A??? i ??|?C???^?l??????? */ /* set_one ???A????????l?? 1 ???X???? */ printf ( "i = %d\n", i ); return 0; }
#include <stdio.h> int main(int argc, char *argv[]) { int i; printf ( "&i = %p\n", &i ); /* &i は (int *) 型のポインタ値 */ printf ( "&i + 1 = %p\n", &i + 1 ); /* &i + 1 のアドレス値は、 sizeof (int) だけ増える */ printf ( "(char *)&i = %p\n", (char *)(&i) ); /* キャスト : 式の前に「(型名)」と記述する事により、 その式の値の型を強制的に、その指定した型にする事ができる */ printf ( "((char *)&i) + 1 = %p\n", ((char *)&i) + 1 ); /* ((char *)&i) + 1 のアドレス値は、 sizeof (char) だけ増える */ return 0; }
#include <stdio.h> int main(int argc, char *argv[]) { char line[10]; /* 文字の配列 : 文字列を保存するために利用 */ gets ( line ); /* キーボードから一行入力して、line に保存 */ /* 文字列の入力 */ printf ( "%s\n", line ); /* 入力した文字列の表示 */ /* puts( line ) でもよい */ /* 保存するための領域は 10 byte ( 9 文字の長さ ) しか 用意されていないのに、それ以上の文字がにゅうりょくできて しまう .. */ return 0; /* 準備していない領域も書き換えられる(ポインタを利用しているから) gets は、その意味で「危険」な関数 fgets を利用するか、scanf で、文字列サイズを指定.. だからといって、利用される領域のサイズをあらかじめ予測するのは難しい 配列のサイズは、コンパイル時に決定されている必要があるので、 予測不能なサイズの情報を保持するのには適さない。 => 実行時に必要なサイズを確保する方法がある => malloc / free (動的なメモリ確保) */ }
#include <stdio.h> #include <malloc.h> /* malloc/free を利用するためのヘッダ */ int main(int argc, char *argv[]) { char *line; /* (char *) 型の変数 : ポインタ値を保持 */ int len; /* 文字列の長さ */ printf ( "入力する文字列の長さを入力してください : " ); scanf ( "%d\n", &len ); line = malloc ( len + 1 ); /* 文字 + EOS のサイズ */ /* 動的に、メモリを確保 */ fgets ( line, len + 1, stdin ); /* キーボードから文字列を入力 */ printf ( "「%s」", line ); /* \n がないのは、fgets が改行も読み込むので.. */ free ( line ); /* 確保した領域を解放 */ /* 記憶領域は、動的(プログラム実行時)に決める事も可能(malloc/free) 確保したら、開放する必要がある */ return 0; }
[前回まで] メモリモデル # メモリ:実在するものをモデル化 # アドレスで操作ができる # サイズ持っている # 情報を記録できる # => 「変数」という「概念」につながってゆく メモリを操作するには、アドレスがあればよい アドレス => C 言語では、「変数名」に相当する メモリ : 1 byte のセルが並んでいる 個々のセルは、アドレスで区別できる 個々のセルは 1 byte の情報を個別に記録可能 read/write 可能 メモリ C 言語 情報の記録 メモリセル 変数 区別 アドレス 名前 区別の形 数値 ラベル?(区別はできても操作できない) 処理 色々可能 区別しかできない 計算 関数の引数に渡せる 関数の値にできる C 言語では、基本は「変数」という抽象化がおこなれている => ほとんどの場合は、その背景である、メモリを意識する必要がない needs : メモリモデルを意識しないとできない事がある 文字列に + 1 すると、長さが短くなる理由 scanf で、変数の前に & を付ける理由 最初は、おまじない => メモリモデルを利用するとわかる seeds : メモリモデルを具体的に処理する機能が用意されている C 言語では、 変数名からそのアドレスを取り出す演算 & 逆に アドレスから、変数のように値を参照したり、変更可能にする演算 * が用意さている。 => メモリモデルを意識したプログラムが作れる [今日の話] メモリを意識したプログラミング & を利用する事により、変数のアドレスを見ることができる 値は、 %p で表示して、確認できる p-001.c ? p-005.c 基本、変数が異なれば、アドレスも異なる => 個々の変数は、別々に値を保持できる(独立) 特に、関数の呼び出し側と呼び出される側も、異なるメモリを利用 => 互いに独立 <= 「値」を共有するために、「引数変数」に「値」がコピーされる 変数に対応する領域は、「再利用」される 関数の中の変数は、関数呼び出しが行わた時点で有効(他の用途に利用されない事が保証される..)になり、関数から帰ると、無効(その領域は、再利用可能な形になる..)になる。 => 変数の「生存時間」と呼ぶ => 変数に対応するメモリ領域は、何度か再利用される => 「前の利用のごみが残っている」ので「初期化忘れ」が問題となる 再帰呼び出し 関数の呼び出しがあるたびに、関数で利用される変数には、 別のメモリ領域が割り当てられる => 再帰呼び出しを可能とする原理 「アドレス値」 メモリ上のアドレスを表す値(%p)で表示されたもの 「ポインター値」 数値の大きさとしては、アドレス値を持つが、それと一緒に、 「型」情報を持っている !! & 演算子 : 変数からアドレス値をとる => 変数から、ポインタ値を取り出す演算子 int 型の変数に & を付けた結果得られる値(ポインタ値)の型は、 (int *) 型になる # 「int *pi」と書くと、変数 pi は(int *) 型になる # これは、 「*pi が、int 型になる」という意味 # 「int *p」=> 「(int *)p」なので、p は(int *)型 # 「int *p」=> 「int (*p)」とすると(*p) が(int)型 ポインタ型の値は、アドレス値と同時にそれがどの型の 変数のアドレスかの(型)情報を保持している # アドレス値は、単なるアドレスなので、 # そのさしている先が、何の型かの情報を持っていない 「ポインター値」 = アドレス値 + 型 = サイズ + 演算の手段 !! 「型」: コンパイル時(C 言語)の概念 !! アドレス値(サイズ) : 実行時(メモリモデル/CPU)の概念 !! => コンパイルによって、これらの情報は失われる(別の形になる) !! 特に !! 関数の引数に渡されるものは、「値」(型情報はない) !! 関数の呼び側と受け側が異なるように扱えててしまう !! # 利点と欠点がある(ほぼ欠点だが..) ポインタ値の操作 アドレス値の操作 ( 加算・減算 ) 型情報の操作 キャスト [まとめ] ポインター値 変数の保存されているメモリのアドレス(アドレス値)と、 その変数の型の情報の組み合わせの事 ただし、型情報はコンパイル時のみ保持され、実行時は、アドレス値しかない 関数の値として、渡されるのは、アドレス値だけ => 両側で、型情報の了解が必要 T 型の値を保持する変数のポインタ値の型は (T *) 型となる 操作としては、 アドレス値の変更 (加算減算) 型情報の変更(キャスト) が可能 変数から、ポインター値(&:アドレス演算子) ポインター値から変数(*:間接参照演算子) の双方向の変換が可能 特に、関数間で、「変数」そのものを渡す事ができないが、 「変数」の「ポインター値」は渡せる => 関数内で、ポインター値を経由する事により、 関数の外の変数の値も(参照と)変更が可能 ==
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20190111-01.c
/* * 課題 CNAME-01 * * 2019/01/11 FILENAME * * 三角形の形をした配列 * */ /* * 利用方法 * コンパイル * 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; }
$ ./20190111-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 : 20190111-02.c
/* * 課題 CNAME-02 * * 2019/01/11 FILENAME * * 動的なメモリの確保 * キーボードより正の整数を幾つか入力して、その要素が入った配列を返す * 0 以下の整数が入力されたら、終了とする * 配列のサイズは、正の整数の個数 + 1 とし、最後の要素には 0 を入れる */ /* * 利用方法 * コンパイル * cc -I ~/c/include -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
$ ./20190111-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 $