[おしらせ] 1. 講義資料と講義内容がかなりずれる 内容の方が遅れている => 今回は、資料の更新はなくて => 以前の資料で 2. 学期末なので、そろそろ、残りのスケジュール => 次回、残りのスケジュールの話を予定している [前回(2019/11/29)の内容] 「配列名」の役割 (関数への実引数としての『関数名』) 関数の呼出し元と呼出し先の「『配列要素』の共有」 複数の値をまとめる 構造体は、いくつでも、それから、どんな組み合わせでもまとめる事ができる cf. 数学の「直積」は、「構造体」と同様な枠組み 一方 配列は、同じ型のデータの組み合わせしかできない => データの表現能力としては、構造体の方が優秀 # 構造体でも、「同じデータの組み合わせ」が可能 cf. 情報の立場 : なにか悪ければ、なにか良い(なにか良ければ、ないか悪い) => C 言語では、「配列」は、([]を利用した間接参照が可能になるので, それを直接利用して)関数の呼び元と呼び出し先が「変数(配列要素)」を「共有できる」 というメリットが生じる 「応用(配列名を利用して、配列要素を共有する)」 「文字列」の入力 # 入力 : (キーボードなどのプログラムの)外から値を得、それを変数に保持する # それを「関数で行う」=> 関数の呼び出し元の変数の値が変化する #「文字列」は、「文字配列」で表現されている # "abc" => char str[4] = { 'a', 'b', 'c', '\0' } # 関数に(文字列を保持する)文字配列を指定して、その文字配列の個々の要素に # 文字コードを代入する事に相当する 文字列の入力の典型的な方法は scanf ( "%s", str ); !!! str の前には & は不要 => scanf ( "%10s", str ); 入力する文字の個数を指定する gets ( str ); !!! あまりにも危険なので、利用不可になった fgets の利用 fgets( str, STR_MAX, stdin ); !!! stdin : 不問 !!! 比数に、配列サイズを指定する事により、 !!! 事前に用意した配列のサイズを超えて、入力がされない !!! # 入力されたデータを保持する変数が変更されないようにする [本日] # 前回(2019/11/29)の資料 「ポインター」とは何か ? メモリモデルの理解 メモリモデルにおけるアドレス(番地) => 「ポインター値」の定義 メモリ(コンピュータの主記憶) 一つのセルに 1 byte ( 8 bit ) の情報が記録できて そのセルが並んでいるものがメモリ 個々のセルには、そのセルを指す番号がつけられていて、それをそのセルの番地(アドレス)と呼ぶ 個々のセルは、(C 言語の変数と同様..) 値を保持できて 代入して、値を変更できる 代入によって、もともとセルが記録していた値は、失われる 参照して、値を取り出す事ができる 値を取り出しても、記憶されている値は失われない # 実は、「C 言語の変数」は、「(1 以上の)セル(の並び)」に対応している # char 型の変数は、1 つのセルと同じ # 32bit cpu の場合は 1 つの整数型の変数は、4 byte ( 4 x 8 = 32bit ) のセルに対応 # 「C 言語」では、整数型は、その言語が使われるシステムで、もっとも都合がよいサイズが使われるという約束 C 言語の「変数」は、メモリの「セル」 C 言語では、「変数名」を指定するが、メモリモデルでは、「番地」を指定する 代入文 (=) の 右に変数名が現れた場合は、その変数の値を意味する が、 左に変数名が現れた場合は、その変数の場所を意味して、 その場所(番地で指定された)の値を書き換えている !!! 関数の引数に「変数名」を書いても、 !!! これは、代入文の右に書いた場合と同じく、値が取り出される !!! => 変数の場所に関する情報は、関数に知る事はできない !!! => 呼び出し元の変数の値が変更できない !!! <= 変数の「場所」が分ければ、それを使って、変更可能なる メモリモデル立場 セルの内容を参照したり変更したりするためには、その番地がわかればよい C 言語の変数は、メモリのセルに対応 C 言語の変数への参照や代入は、「変数名」を経由して行われる # Cコンパイラが、「変数名」と「アドレス」の対応付けを行っている => 「変数名」が見えないところでは、「変数」を操作できない !!! 関数呼び出しでは、「変数」から「値を取り出」し、 !!! その「値」だけを、関数の仮引数変数に代入している !!! => 「変数名」がみえない関数内では、その変数を操作できない コンパイラは、 「変数名」だけでなく、「番地の情報」ももっているので、 番地から変数、変数から番地の相互の変換が可能で 「変数名」から「番地の情報」を得る演算子 : & 「番地の情報」から「変数名」を得る演算子 : * & * 「変数名」=> 「番地」 => メモリアクセス 配列名 : 配列の先頭要素のアドレスを表す 「番地」という考え方を(配列に限定せず)一般的に扱う事ができると より便利だという事ができる 変数の利用 :「変数名」=> メモリアクセス [まとめ] 「ポインター値」とは何か ? 変数のある場所(メモリモデルにおける番地)に対応している %p で表示されるのは、本当(コンピュータのメモリ)の番地が表示される + * を付けた時に、その場所にあるセル(の集まり)が参照できる cf. char * : char へのポインター型の場合 1 byte int * : int へのポインター型の場合は 4 byte だけ参照される !!! 単なるアドレスだけでなく、そのアドレスにあるデータ型に関する情報が付加されたもの !!! 同じアドレス値をもっていても、参照する型が異なれば、異なる振る舞いをする 「ポインター」とは何か ? ポインター値を持つ変数