C言語入門

1
C言語入門
第6週
プログラミング言語Ⅰ(実習を含む。),
計算機言語Ⅰ・計算機言語演習Ⅰ,
情報処理言語Ⅰ(実習を含む。)
2
第3週資料の復習
1次元配列
3
教科書 pp.85-108.
配列変数
• 同じ変数名で複数の要素を管理する
char a[10]; // 要素数10のchar型変数の宣言
初期値式が与えられなかった場合、値は不定
?
?
?
?
a[0]
a[1]
a[2]
a[3]
?
...
要素数10の添え字付き変数
a[9]
[1] pp.103-104., p.273.
4
教科書 pp.85-108.
配列変数
• 配列変数の要素への代入
char a[10]; // 要素数10のchar型変数の宣言
a[0] = 'a'; // 0番目の要素へ代入
宣言後の代入
初期値式が与えられなかったので、値は不定
'a'
?
?
?
a[0]
a[1]
a[2]
a[3]
?
...
要素数10の添え字付き変数
a[9]
[1] pp.103-104., p.273.
5
教科書 pp.85-108.
配列変数
• 添え字は値が取れれば変数や数式でも良い
int i = 1;
char a[10]; // 要素数10のchar型変数の宣言
a[i + 1] = 'a'; // 2番目の要素へ代入
?
?
'a'
?
a[0]
a[1]
a[2]
a[3]
?
...
要素数10の添え字付き変数
a[9]
[1] pp.103-104., p.273.
6
教科書 pp.85-108.
配列変数
• 確保した領域外はアクセスは禁止
char a[10]; // 要素数10のchar型変数の宣言
short b = 0x1234;
a[10] = 'a';// 宣言された領域外へのアクセス
?
?
?
?
a[0]
a[1]
a[2]
a[3]
ここに書き込むと何が起こるか分からない
0x1234
?
'a'
b
a[9]
a[10]
...
他の変数が使っていたらその値を壊してしまう
要素数10の添え字付き変数
[1] pp.103-104., p.273.
7
教科書 pp.85-108.
配列変数
• 初期値式による配列変数の初期化
char a[10] = {'a', 'b'}; //初期値式付きの
//要素数10のchar型変数の宣言
初期値式による初期化
初期値式が要素数より少ない場合、残りは0で初期化
'a'
'b'
0
0
a[0]
a[1]
a[2]
a[3]
0
...
要素数10の添え字付き変数
a[9]
[1] pp.103-104., p.273.
8
教科書 pp.85-108.
配列変数
• 初期値式による配列変数の初期化
char a[] = {'a', 'b'}; //初期値式付きで
//要素数を省略したchar型変数の宣言
初期値式による初期化
'a'
'b'
a[0]
a[1]
初期値式の要素数分確保される
[1] pp.103-104., p.273.
9
教科書 pp.85-108.
配列変数
• 文字列による初期化(要素数指定)
char a[10] = "ab";
文字列と文字列終端の'\0'
//文字列による初期値付きの
//要素数10のchar型変数の宣言
初期値式が要素数より少ない場合、残りは0で初期化
'a'
'b'
0
0
a[0]
a[1]
a[2]
a[3]
0
...
要素数10の添え字付き変数
a[9]
[1] pp.103-104., p.273.
10
教科書 pp.85-108.
配列変数
• 文字列による初期化(要素数自動決定)
char a[] = "ab";//文字列による初期値付きで
//要素数を省略したchar型変数の宣言
文字列と文字列終端の'\0'
'a'
'b'
0
a[0]
a[1]
a[2]
文字列の文字数+文字列終端'\0'の1文字分の要素
[1] pp.103-104., p.273.
11
変数の初期化
• 明示的な初期化がない場合
• 外的変数、静的変数→0
• 自動変数、レジスタ変数→不定
• 初期化する場合
• 外的変数、静的変数←定数式でのみ初期化可
• コンパイル時に1度だけ初期化される
• 自動変数、レジスタ変数←任意の式で初期化可
• 実行時にブロック毎に初期化される
[1] pp.103-104., p.273.
12
配列変数の初期化
• 要素数を与えない場合
• 初期値式の数で配列のサイズが決まる
• 要素数を与えた場合
• 初期値式を与えない場合
• 値は不定
• 初期値式を与える場合
• 要素数を超えるとエラー
• 要素数に足りない部分は0で初期化される
[1] pp.103-104., p.273.
13
配列の初期値と配列の初期化の範囲
配列の初期化についての確認
14
確認: a の値はどうなるか?(1/5)
• array_ex1.cを実行し以下の事を確認しなさい
• s1: そのまま実行するとどうなるか?
• s2: 6行目の初期化だけアンコメント(途中の/*と*/
を削除)するとどうなるか?
• s3: 7行目だけアンコメント(先頭の//を削除)すると
どうなるか?
• s4: 上記6行目7行目の両方をアンコメントするとど
うなるか
• 上記4つの場合において bcc32 の場合は -O2 オ
プション gcc の場合は -O3 をオプションを付けて
コンパイルすると結果はどう変わるか?
-O2, -O3 は最適化(optimization) を
施すためのオプションである。
15
確認: a の値はどうなるか? (2/5)
• 以下の4通りの場合について確認
array_ex1.c
s1
array_ex1.c
6 char a[4]/* = {'a', 'b'}*/;
7 //a[0] = 'c';
array_ex1.c
s3
s2
6 char a[4] = {'a', 'b'};
7 //a[0] = 'c';
array_ex1.c
6 char a[4]/* = {'a', 'b'}*/;
7 a[0] = 'c';
全部で
4 * 4 = 16 パターン
s4
6 char a[4] = {'a', 'b'};
7 a[0] = 'c';
• 以下の4通りの場合について確認
mintty + bash + GNU C
c1
$ gcc array_ex1.c && ./a
mintty + bash + GNU C
c3
$ gcc -O3 array_ex1.c && ./a
cmd + BorlandC++
c2
> bcc32 array_ex1.c && array_ex1
cmd + BorlandC++
c4
> bcc32 -O2 array_ex1.c && array_ex1
16
確認: a の値はどうなるか?(3/5)
• 例えばs3s3,s4c3の場合以下のようになる
mintty + bash + GNU C
$ gcc
a[0]:
a[1]:
a[2]:
a[3]:
-O3 array_ex1.c && ./a
0x63: 'c'
0xcb: '▒'
0x22: '"'
0x00: ''
mintty + bash + GNU C
$ gcc
a[0]:
a[1]:
a[2]:
a[3]:
s3c3
s4c3
-O3 array_ex1.c && ./a
0x63: 'c'
0x62: 'b'
0x00: ''
0x00: ''
s3 の状態ではa[1]~a[3] に対し初期
化も代入もされていないので、たまた
まこの値になっただけである点に注意。
つまりこの値は未定である。
s4 の状態でも一見 a[2], a[3] に対し
初期化も代入もされていないように
見えるが「初期値式が要素数より少
ない場合、残りは0で初期化」という
ルールが適用されるためたため実際
には確実に 0x00 となる事が保証さ
れる。
17
確認: a の値はどうなるか?(4/5)
• 例えばs3s3,s3c1の場合以下のようになる
mintty + bash + GNU C
$ gcc
a[0]:
a[1]:
a[2]:
a[3]:
-O3 array_ex1.c && ./a
0x63: 'c'
0xcb: '▒'
0x22: '"'
0x00: ''
mintty + bash + GNU C
$ gcc
a[0]:
a[1]:
a[2]:
a[3]:
s3c3
s3c1
array_ex1.c && ./a
0x63: 'c'
0x00: ''
0x00: ''
0x00: ''
ソースコードは同じs1の状態なのにコ
ンパイル時のオプションの有無で値が
変わっている点に注意。
このように未定の値は実行してみるま
でどうなっているか分からない。
18
確認: a の値はどうなるか?(5/5)
s
1
2
3
4
1
2
3
4
1
2
3
4
1
2
3
4
c
1
1
1
1
2
2
2
2
3
3
3
3
4
4
4
4
a[0]
0x63
0x63
0x63
a[1]
0x00
0xcb
0x62
a[2]
0x00
0x20
0x00
a[3]
0x00
0x00
0x00
上記で赤字で示した箇所は本来
未定となる箇所。
つまりたまたまその値になっただ
けに過ぎない点に注意。
19
一次元配列の演習
ベクトルの演算
20
演習: ベクトルの演算
• 𝒂, 𝒃 を𝑥, 𝑦, 𝑧の3次元ベクトルとしたときに以下の計
算を行うプログラム作ってみましょう。
• 加算(add)、減算(sub)、
内積(dot product)、外積(cross product)
𝒂 + 𝒃 = 𝑎𝑥 + 𝑏𝑥 , 𝑎𝑦 + 𝑏𝑦 , 𝑎𝑧 + 𝑏𝑧
𝒂 − 𝒃 = 𝑎𝑥 − 𝑏𝑥 , 𝑎𝑦 − 𝑏𝑦 , 𝑎𝑧 − 𝑏𝑧
𝒂 ⋅ 𝒃 = 𝑎𝑥 𝑏𝑥 + 𝑎𝑦 𝑏𝑦 + 𝑎𝑧 𝑏𝑧
𝒂 × 𝒃 = 𝑎𝑦 𝑏𝑧 − 𝑎𝑧 𝑏𝑦 , 𝑎𝑧 𝑏𝑥 − 𝑎𝑥 𝑏𝑧 , 𝑎𝑥 𝑏𝑦 − 𝑎𝑦 𝑏𝑥
21
演習: ベクトルの演算
• 結果は result[0] または result[0~2]
に格納しましょう。numresult を適宜設定してく
ださい。
• 雛形(vector_xxx_practice_1.c)をダウン
ロードして指定された箇所に実装してください。
• ファイル名は、以下の名前にしましょう。
•
•
•
•
加算:
減算:
内積:
外積:
vector_add_practice_1.c
vector_sub_practice_1.c
vector_dot_practice_1.c
vector_cross_practice_1.c
22
演習: ベクトルの演算
• 動作テスト用のスクリプト
•
•
•
•
加算:
減算:
内積:
外積:
vector_add_practice_1_test.sh
vector_sub_practice_1_test.sh
vector_dot_practice_1_test.sh
vector_cross_practice_1_test.sh
23
演習: ベクトルの演算
• ヒント: 書き方はいろいろある。
ループを用いない add
ループを用いた add
result[0] = a[0] + b[0];
result[1] = a[1] + b[1];
result[2] = a[2] + b[2];
for (i = 0; i < M; i++) {
result[i] = a[i] + b[i];
}
24
参考文献
• [1] B.W.カーニハン/D.M.リッチー著 石田晴久
訳、プログラミング言語C 第2版 ANSI 規格準
拠、共立出版(1989)