2019/11/22 # 実は.. 今日は、「今日から、この講義は新しい局面に入った」で始める予定だった.. # でも、まあ、.. 電車が遅れているようなので、時間稼ぎ [やりそこねていた内容(試験に関係部分)] 2019/09/27 の squash の話 c:\usr\c の所に、squash.zip をダウンロード windows から、右クリックして[すべて展開]をする squash というフォルダが作られる ubuntus cd c/squash make パスワードをきかれたら、いつものように「soft」と入力 うまくいったら.. make test スカッシュゲームが開始される 操作方法など ( readme.txt を参照 ) [l] -> 右に移動 [h] -> 左に移動 [q] -> ゲーム終了 ゲームとしては、キーボードを利用して、パドルを左右に操作し、 ボールを打ち返す [squash.c の説明] 必要なライブラリ curses : text ベースで、画面描画操作を行うためのライブラリ # printf は、画面に新しい文字列を追加する事しかできない # <-> curses を利用すると、画面の任意の文字が上書きできる # => charactor base のゲームを作る事ができる ## [いいたいこと] ## curses というおもしろいライブラリの紹介 ## 色々機能が、ライブラリの形で提供されているので、探してみよう curses の API (Application Program Interface : ライブラリを使うプログラムとライブラリの間の約束事 : ライブラリの使い方) move(Y,X) : カーソル(次に文字を表示する)位置を Y 行 X 桁にする refresh(); : 画面の更新を行う # curses を利用して描画命令をおくっても、実は、かくれ画面の内容が # 更新されるだけで、実際の画面には、反映されない(ちらつきを避けるため) # refresh() によって、変更した内容を、画面に反映させる事ができる # printf はカーソルの位置(表画面に直接) addch( ch ) : 現在のカーソルの位置に、文字 ch を表示する 画面の初期化の命令がいくつか initscr(); /* 画面を初期化 (クリアされる) */ cbreak(); /* 文字の入力をリアルタイムにする */ 入力命令が実行されたとき(普通は、入力があるまで待つが..)、 この関数(1度だけ最初に呼ぶだけで、以降..) またなくなる noecho(); /* 文字の入力をエコーバックしない */ timeout(0); /* 文字の入力がなければ直ぐにかえる */ getch() : キーボードから、入力して入力された文字コードを返す関数 getchar() とはちがい、初期化の設定に従って、 入力がなければ、すぐに、終了して、\0 (入力なし)を返す endwin(); /* curses の後始末 */ 特に、入力関係などの設定、標準状態にもどしてくれる == [前回まで] # C 言語の習得の二大課題(ポインターと再帰呼び出し) # 今日の内容から「ポインター」を理解するための準備を始める [配列] 複数の変数をまとめて、扱う事ができる(データ構造) int a[3]; /* a という整数型の要素を持つ配列を宣言 */ /* -> a[0], a[1], a[2] という三つ変数が利用できるようになる */ /* int a0; int a1; int a3; と、三つの変数を宣言すると同じ.. */ a[0] = 1; /* a0 = 1 */ a[1] = a[0]+2; /* a1 = a0 + 2 */ /* 配列 a に対して、a[0], a[1], a[2] を配列の要素と呼ぶ */ /* 配列の要素を参照する場合、[]の中(添え字)には「整数式」が利用できる */ /* 間接参照(添え字を指定して、変数を選択している) */ /* <=> 直接参照(変数を「変数名」を直接指定する事により選択している) */ /* !! 配列では、添え字を利用して間接参照できる事が、 !! 単なる「変数の集まり」とは異なる !! !! => 「ポインター」が強力な理由も同じ */ /* 間接参照ができる => 参照先を実行時に計算で求める事できる */ /* <= 直接参照の場合は、プログラム時に決まってしまう */ 配列の要素が、添え字を利用して、参照できる => for 構文の相性が非常によくなる # for 構文は、配列を利用するためにしつらえた構文 [今日の話] 「配列の引数渡し」 復習 : 課題 2019/11/08 課題 3 関数の引数には、配列名を指定する事ができる => あたかも、(他の例では、引数に指定したもののコピーが渡されるように見えるにも変わらず) 「配列そのもの」が渡されるように、見える !! 関数の引数は、「値」が渡されるので、「変数そのもの」が渡るわけではない !! => にも関わらず、「配列名」を指定した場合に、「配列の要素そのもの」が渡されるように見える仕組みは何か ? !! # 「変数そのもの」 <=> 「関数内での変数の値への変更が、呼び出し元に反映される」 改めて、「配列の要素の参照」 int a[3]; /* a[0], a[1], a[2] */ a[1]; /* 添え字を配列名に指定すると、その要素が参照できる */ *(a+1) /* 「a[1]」 <-> 「*(a+1)」 */ /* 「もし」、「a(配列名)」が何等かの「値」をもっている */ /* 引数に指定しれば、その「値」(のコピー)が渡される */ void sub ( int y[3] ) { /* y という「配列」ではなく、「配列名が表す値を保持する変数」だと解釈すると */ y[1] => *(y+1) => *(a+1) => a[1] と同じ振る舞いをする事になる } sub ( a ); /* 配列名を指定すると a の値が y に代入される */ /* !!!! 「配列名」を指定しても、「配列のサイズ」は決まらない */ 関数の引数に、「配列名」を指定すると 関数の中で、その「『配列名』が表す値」を利用する事できて、 その「『配列名』が表す値」を利用して、間接的に、「配列の要素」を変更する事ができる => 関数呼び出しによって、呼び出す側の変数(配列の要素)の値が変更される事がおきるうる [まとめ] 関数の引数に、「配列名」を指定する事ができる 関数の中では、その「関数名が持っている『要素を参照するために必要な値』」を利用して、 その「配列名が表す『配列の要素』を参照(値を取り出すだけでなく、値の変更[代入]も)可能」 => この結果、 関数では、配列のサイズと独立して動く機能が実現できる そのために、処理の範囲(配列のサイズである事が多いが、それに限らない) を別に指定する必要がある !! [副作用] !! 悪し : 関数の呼び出し元と、関数内での配列(の要素)が「共有」される !! 良し : コピーがおきないので、効率が良い