C言語入門

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