02: 変数と標準入出力

C プログラミング入門
基幹2 (月4)
07: 配列
Linux にログインし、以下の講義ページ
を開いておくこと
http://www-it.sci.waseda.ac.jp/
teachers/w483692/CPR1/
2014-05-26
1
復習:メモリと変数
メモリの一部に名前を付けて、数値を格納す
る機能=変数
int year = 2014;
位置は自動的に決定される
表現できる値は型で規定
メモリ上でのサイズは型依存
double value;
char ch = 'C';
初期値を与えない場合は不定
変数名
初期化しない場合、値として何が入っているかはわからない
year
2014
value
ch
??
'C'
それぞれの位置は自動で決まるので、並んでいるとは限らない
2014-05-26
C プログラミング入門 基幹2 (月4)
2
配列変数
複数個の値を連続して格納する変数
1つ1つを要素 (element) という
要素はインデックス (index) という整数で区別
各要素をインデック
最初の要素のインデックスは 0
スで区別
scores
配列変数名
scores[0]
scores[1]
scores[2]
scores[3]
100
95
55
43
score1
100
2014-05-26
score2
95
score3
55
score4
43
C プログラミング入門 基幹2 (月4)
4人のスコアを
配列変数で格
納した場合
4人のスコアを
4つの変数で格
納した場合
3
配列変数の定義 (array)
構文
型名 変数名[要素数];
普通の変数名と同じ名前は使用できない
日本語では 0
オリジンとい
う。英語では
zero-based
などと呼ぶ
インデックスは 0 から始まる
要素数 n の配列の最後の要素のインデックス
は n-1
score[4] はない
{
scores[0]
int score[4];
??
scores[2]
??
??
scores[1]
2014-05-26
C プログラミング入門 基幹2 (月4)
??
scores[3]
4
配列の初期化
初期化には特別な構文を用いる
指定する初期値が足りない場合は残りはすべて 0
となる
4つの要素の初期値は不定
a
{
?
int
int
int
int
int
a[4];
b[4] = { 100, 50, 20, 1 };
c[4] = { 100, 50 };
すべてゼロに
d[4] = { 0 };
する場合
e[] = { 100, 50, 20, 1 };
2014-05-26
?
?
50
0
0
0
0
0
c
100
d
0
要素数を省略すると初期化の要素数となる
int f[4] = { 1, 2, 3, 4, 5 };
?
エラー
C プログラミング入門 基幹2 (月4)
足りない分は
すべて0となる
5
配列変数のアクセス
配列変数の各要素へは通常の変数と同じよう
にアクセスできる
配列全体への代入はできない
{
int a[4] = { 100, 50, 20, 1 };
int sum;
要素への代入
a[0] = 99;
要素の値を読む
printf("%d", a[0]);
計算式に要素の値を使う
sum = a[0]+a[1]+a[2]+a[3];
a = { 100, 50, 20, 1 };
2014-05-26
エラー。配列に値を一度に設定する代
入演算子はない
C プログラミング入門 基幹2 (月4)
6
配列変数とループ
配列の利点として、ループでアクセスできる
ループ変数にインデックスを対応させる
格納される値
{
int tri[10], i;
tri[0] == 0
i=3
tri[1] == 1
for(i = 0; i < 10; ++i)
{
tri[i] = i*(i+1)/2;
}
2014-05-26
tri[2] == 3
tri[3] == 6
tri[4] == 10
この数列を三
角数という
tri[5] == 15
...
C プログラミング入門 基幹2 (月4)
7
範囲外アクセスの注意
配列のアクセスではインデックスの範囲は
チェックされない
範囲外の値を読んだり、書きこんだりするこ
とは理由がない限り避ける
場合によってはシステムが検知してセグメンテー
ションフォルト (segmentation fault; SEGV) 例
外が発生してプログラムが強制終了する
a[-1] としてアクセスできるが
なにが入っているかは不明
a[0]
100
2014-05-26
95
55
a[4] としてアクセスした場合、
意味のある値としては読めない
a[3]
43
pi
3.14
C プログラミング入門 基幹2 (月4)
このようなアク
セスを意図的に
行う場合もある
8
配列変数の要素数
配列変数の要素数には限界がある
環境依存。せいぜい数千~数万要素程度
巨大な領域を取るには動的メモリを用いる
今後説明
配列サイズを変更できない
プログラムの実行中に変更が必要な場合は、より
高度なデータ構造を使う必要がある 秋期の講義で扱う
配列のコピーを行う構文はない
コピーを行う標準ライブラリ関数を用いる
2014-05-26
C プログラミング入門 基幹2 (月4)
今後説明
9
配列の要素数とリテラル
C89 では要素数は
リテラルでのみ指
定可能
変数で指定すること
は禁止されている
GCC は独自拡張で
許容している
C99 以降は可能
実用上、変数を使って困ることは少
ないので、この講義でも場合によっ
ては使うことがある
2014-05-26
要素数とループ
の式を変数 n で
統一できる
{
int n = 10;
int tri[n], i;
for(i = 0; i < n; ++i)
{
tri[i] = i*(i+1)/2;
}
-pedantic オプ
ションで無効化
できる
C プログラミング入門 基幹2 (月4)
10
多次元配列
インデックスを複数使う配列
全部で 6 (=3×2) 要素
{
int A[3][2] = { {1,2}, {3,4}, {5,6} };
各要素がさらに 2 要素
に分かれている
全体として 3 要素
int B[3][2] = { { 0 } };
A[0][0]
1
A[1][0]
2
3
全ての要素を 0 で初期化する場合
A[2][0]
4
5
6
A[1][1]
A[2][1]
A[0][1]
メモリ上では初期化と同じ順に並ぶ
2014-05-26
行列で考えた場合の
イメージ
𝑎00 𝑎01
𝐴 = 𝑎10 𝑎11
𝑎20 𝑎21
C プログラミング入門 基幹2 (月4)
11
多次元配列のアクセス
宣言と同じ書式でアクセスする
A[2,1] と書いても、これ自体はコンパイル
エラーとならない。なぜなら、 "2,1" はカン
マ演算子の式とみなされるためである(前回
参照)。しかし、結果として、 A[1] と同じ
意味になるが、この式の評価は意図したもの
ではないので(次回以降説明)結局、別の意
味でエラーとなる。ただし、この場合、エ
ラーメッセージの意味がわかりづらくなる。
{
int A[3][2];
A[0][0] = 1;
A[2][1] = 6;
A[0][0]
1
A[1][0]
?
A[0][1]
2014-05-26
?
A[2][0]
?
A[1][1]
?
6
A[2][1]
行列で考えた場合の
イメージ
𝑎00 𝑎01
𝐴 = 𝑎10 𝑎11
𝑎20 𝑎21
C プログラミング入門 基幹2 (月4)
12
例題: マルバツゲーム (Tic-tac-toe)
3 × 3 の盤面を配列で表現
配列の値
意味
値の意味を右の表の通りと決める
0
空欄
1
○
{
2
×
それ以外
使わない
int board[3][3] = {{0}};
全要素をゼロ
int i, j;
で初期化
board[0][2] = 1; // O
board[1][1] = 2; // X
// 盤面の表示
// ...どう書く?
2014-05-26
board[0][2]
出力
..O
.X.
...
board[1][1]
C プログラミング入門 基幹2 (月4)
13
例題: マルバツゲーム (Tic-tac-toe)
// 盤面の表示
for(i = 0; i < 3; ++i)
{
for(j = 0; j < 3; ++j)
{
if(board[i][j] == 0)
{ printf("."); }
else if(board[i][j] == 1)
{ printf("O"); }
else if(board[i][j] == 2)
{ printf("X"); }
..O
}
.X.
printf("\n");
...
行ごとの改行
}
2014-05-26
配列の値
意味
0
空欄
1
○
2
×
それ以外
使わない
board[0][2]
出力
board[1][1]
C プログラミング入門 基幹2 (月4)
14
例題: マルバツゲーム / コードの工夫
// 盤面の表示
for(i = 0; i < 3; ++i)
{
あらかじめ変数
for(j = 0; j < 3; ++j)
に入れておく
{
int x = board[i][j];
if(x == 0) { printf("."); }
else if(x == 1) { printf("O"); }
else if(x == 2) { printf("X"); }
}
printf("\n");
比較の式が読
みやすくなる
}
このような分岐コードは、 swichcase を用いることもできる。講義
では説明しない。
2014-05-26
配列の値
意味
0
空欄
1
○
2
×
それ以外
使わない
board[0][2]
board[1][1]
C プログラミング入門 基幹2 (月4)
15