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