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
© Copyright 2024 ExpyDoc