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