プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。) C言語入門 第17週 (補講) プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
期末試験問題
C言語のプログラム コンパイラにより実行形式に変換する 第1週資料p.7. いつもgccやbcc32がやってくれている処理の範囲 問1はいつものコンパイル手順を思い出してみると良い コンパイラにより実行形式に変換する .c ファイル .h ファイル Source files Preprocessor 実行ファイル Executable file C compiler .o ファイル Object files linker
アセンブラ 教科書p.17 第2週講義資料 pp.25-26.
初期化・更新処理付きループ (for 文) 真偽値による繰り返し for(式1; 式2; 式3) { // 式2が真の場合の処理 }; 第3週資料p.92. 初期化・更新処理付きループ (for 文) 真偽値による繰り返し 式1 for(式1; 式2; 式3) { // 式2が真の場合の処理 }; 式2 偽 真 処理 問2-1は、forループの処理手順を自分で確かめれば良い 式3
問2-2 y軸のカウントダウン(y--)が出来てない人が多数いた。 境界値の間違いが多数いた <, <=, >=, > の違い 例えば代表値を代入して確認してみる 例: (x,y) = (0,0) や (7,7) 等 (b) $ ./a 7 . . . . . . . # 6 . . . . . . # # 5 . . . . . # # # 4 . . . . # # # # 3 . . . # # # # # 2 . . # # # # # # 1 . # # # # # # # 0 # # # # # # # # y x 0 1 2 3 4 5 6 7 (b) $ ./a 7 . . . . . . . # 6 . . . . . . # # 5 . . . . . # # # 4 . . . . # # # # 3 . . . # # # # # 2 . . # # # # # # 1 . # # # # # # # 0 # # # # # # # # y x 0 1 2 3 4 5 6 7
問2-3 問2-1同様、1つ1つの手順に値を入れて自分で手順を確認してみれば良い。 実は処理を1つ1つ確認しなくても選択ソートのアルゴリズム(=処理手順)を知っていれば分かる問題 未処理の先頭値と、未処理の最小値を交換する 選択ソートの進捗 $ gcc exam_q2_3.c && ./a 0 3 13 2 7 17 11 19 5 1 2 13 3 7 17 11 19 5 2 2 3 13 7 17 11 19 5 3 2 3 5 7 17 11 19 13 4 2 3 5 7 17 11 19 13 5 2 3 5 7 11 17 19 13 6 2 3 5 7 11 13 19 17 7 2 3 5 7 11 13 17 19 赤字: 処理済み 青字: 未処理の先頭 橙字: 未処理の最小値
問3-1 double なのに int にしている人が多数いた 関数呼び出し時に & を付けない人が多数いた(ポインタ渡しにしないと、呼び出し元の変数の内容を変更出来ない)
問3-2 double tmp; と宣言しなければいけないので tmp は double 型であってポインタではない。 tmp の前の '*' を除去して *b = tmp とすれば良い。
問4 以下の何れか 末尾が ; 出ない人が多数いた 適切に型を与えていない(intと書いていない人)も多数いた int factorize(int x, int a[], int n); int factorize(int x, int *a, int n); 末尾が ; 出ない人が多数いた 適切に型を与えていない(intと書いていない人)も多数いた a が a[] や *a 出ない人が多数いた
問5 ポインタ変数 p の使い方 例: p : 代入したアドレスそのもの *p : 代入したアドレスに格納されている値 p = &a なら p は a のアドレス(つまり &a) *p は a の値(つまり a)
問5 ポインタ変数 p の計算 例: p + 1 は? p = &a が 0 で sizeof(*p) が 4 なら つまりpに入っているアドレスにsizeof(*p)を加算した値 例: p = &a が 0 で sizeof(*p) が 4 なら p + 1 は 4
問6-1 関数 main 関数 q6_1 s の先頭からサイズ-1(終端文字\0の手前)までを処理している s の内容を1つづず q6_1 に与えて戻り値を文字コードとして扱い、対応する文字を1文字表示 関数 q6_1 abc~xyz が zyx~cba に入れ替わる アルファベットの小文字以外はそのまま
問6-2 配列の初期化 第3週資料p.73-83.を参照
期末試験実技課題
統計 母集団のすべての標本値 𝑥 𝑖 が𝑖=0~𝑛−1までの𝑛個あるとした場合 (母集団の)平均 (AVR: AVeRage) 母集団のすべての標本値 𝑥 𝑖 が𝑖=0~𝑛−1までの𝑛個あるとした場合 (母集団の)平均 (AVR: AVeRage) 𝑥 = 1 𝑛 𝑖=0 𝑛−1 𝑥 𝑖 (母集団の)分散 (VAR: VARiance) 𝜎 2 = 1 𝑛 𝑖=0 𝑛−1 𝑥 𝑖 − 𝑥 2 (母集団の)標準偏差 (STDEV: STandard DEViation) 𝜎= 1 𝑛 𝑖=0 𝑛−1 𝑥 𝑖 − 𝑥 2 値の合計値 件数 各値−平均 2 の平均 分散の平方根
統計 (母集団の)平均 (AVR: AVeRage) 𝑥 = 1 𝑛 𝑖=0 𝑛−1 𝑥 𝑖 sum = 0; 𝑥 = 1 𝑛 𝑖=0 𝑛−1 𝑥 𝑖 値の合計値 件数 for による積算 sum = 0; for (i = 0; i < n; i++) { sum += x[i]; } avr = sum / n; 積算用変数の初期化 値の積算 値の合計値 件数 ここではsumがdouble型なので暗黙の算術変換(第5週資料p.49)が適用されるが、「整数型 / 整数型」の場合は(double)等のキャストを行わないと結果が整数になる
統計 (母集団の)分散 (VAR: VARiance) 𝜎 2 = 1 𝑛 𝑖=0 𝑛−1 𝑥 𝑖 − 𝑥 2 var = 0; 𝜎 2 = 1 𝑛 𝑖=0 𝑛−1 𝑥 𝑖 − 𝑥 2 各値−平均 2 の平均 for文による積算 var = 0; for (i = 0; i < n; i++) { var += (x[i] - avr) * (x[i] - avr); } var /= n; 積算用変数の初期化 値の積算 値の合計値 件数 訂正: 2014-08-18 19:50 誤: (x[i] - var) 正: (x[i] - avr)
統計 (母集団の)標準偏差 (STDEV: STandard DEViation) 𝜎= 1 𝑛 𝑖=0 𝑛−1 𝑥 𝑖 − 𝑥 2 𝜎= 1 𝑛 𝑖=0 𝑛−1 𝑥 𝑖 − 𝑥 2 分散の平方根 平方根の計算 stdev = sqrt(var);
課題1: calcscore.c 全てまとめると完成 sum = 0; for (i = 0; i < n; i++) { sum += score[i]; } avr = sum / n; var =0; var += (score[i] - avr) * (score[i] - avr); var = var / n; stdev = sqrt(var);
素因数分解 正整数𝑥を因数分解するには 整数𝑦を2以上𝑥未満まで順に増やしながら手順2の処理を繰り返す。 𝑥が𝑦で割り切れるなら𝑥=𝑦×𝑧として𝑦を素因数として保存し𝑧を新たな𝑥とする事を繰り返す。(12=2×2×3の同じ素因数を複数個取り得るため) 最後に残った𝑥も素因数として保存する。ただし、 𝑥=1の場合、かつ保存した素因数が1個以上ある場合𝑥を素因数として保存してはいけない。(4=2×2×1のようになるため) 例: 1 = 1 2 = 2 3 = 3 4 = 2 * 2 12 = 2 * 2 * 3 なおyを2~x未満とした場合 x=7をy=6で割るのは明らかに無駄だが ここでは手順の簡素化を優先している。
素因数分解 整数𝑦を2以上𝑥未満まで順に増やしながら手順2の処理を繰り返す。 for文を使って単純に繰り返せばよい 手順1のループ for (y = 2; y < x; y++) { // y を 2 以上 x 未満まで増やす };
素因数分解 𝑥が𝑦で割り切れるなら𝑥=𝑦×𝑧として𝑦を素因数として保存し𝑧を新たな𝑥とする事を繰り返す。 ここも繰り返しなので手順1と手順2で2重ループとなる 素因数の保存は配列に追加して行けば良い 保存済みの素因数をn個とした時 nは配列の最大要素数を超えてはいけないから エラー処理も必要になる 手順2のループ while (x % y == 0) { // ここでyを保存 x = x / y; //zを新たなxにする } 手順1のループ中で 処理する必要がある
素因数分解 𝑥が𝑦で割り切れるなら𝑥=𝑦×𝑧として𝑦を素因数として保存し𝑧を新たな𝑥とする事を繰り返す。 ここも繰り返しなので手順1と手順2で2重ループとなる 素因数の保存は配列に追加して行けば良い 保存済みの素因数をn個とした時 nは配列の最大要素数を超えてはいけないから エラー処理も必要になる 手順2におけるyの保存処理 if (nmax <= n) return -1; a[n] = y; n++;
素因数分解 𝑥が𝑦で割り切れるなら𝑥=𝑦×𝑧として𝑦を素因数として保存し𝑧を新たな𝑥とする事を繰り返す。 ここも繰り返しなので手順1と手順2で2重ループとなる 素因数の保存は配列に追加して行けば良い 保存済みの素因数をn個とした時 nは配列の最大要素数を超えてはいけないから エラー処理も必要になる 手順2の処理 while (x % y == 0) { if (nmax <= n) return -1; a[n] = y; n++; x = x / y; } 手順1のループ中で 処理する必要がある
条件は「𝑥=1かつ保存した素因数が1個以上ある」以外の場合𝑥も素因数として保存するとも言い換えることが出来る。 素因数分解 最後に残った𝑥も素因数として保存する。ただし、 𝑥=1の場合、かつ保存した素因数が1個以上ある場合𝑥を素因数として保存してはいけない。 if 文で条件分岐させれば良い 条件は「𝑥=1かつ保存した素因数が1個以上ある」以外の場合𝑥も素因数として保存するとも言い換えることが出来る。 素因数の保存とエラー処理については 手順2と同じ 手順3の処理 if (!(x == 1 && 0 < n)) { if (nmax <= n + 1) return -1; a[n] = x; n++; }
課題2: factorize.c 全てまとめると完成 factoraize.c factoraize.h int factorize(int x, int *a, int nmax) { int y, z, n = 0; if (x <= 0) return -1; for (y = 2; y < x; y++) { while (x % y == 0) { z = x / y; if (nmax <= n) return -1; a[n] = y; n++; x = z; } if (!(x == 1 && 0 < n)) { if (nmax <= n + 1) return -1; a[n] = x; return n; 全てまとめると完成 factoraize.h #ifndef FACTORIZE_H #define FACTORIZE_H int factorize(int x, int *a, int nmax); #endif