[先週] 共用体(union) : 二つ(以上)の型の和集合型を作る cf. 構造体(struct) : 二つ(以上)の型の直積集合型を作る 複数の型のデータが入る一つの変数を作る その変数には、一つの値しか入らない cf. 構造体の方は、二つ(以上)の値が入る 制御構造とデータ構造の関係 制御構造 データ構造 順接 構造体 条件分岐 共用体 繰り返し 配列 => 制御構造(プログラム)の裏にデータ構造がある -> プログラムを作るために、データ構造を配慮する事が望ましい 「文字列」と文字配列の関係 「文字列」は、実は、特殊な文字配列の事だった。 文字列は、文字配列に、文字と EOS ('\0')が詰まったもの 特に、"〜" は、その中身が変更できないようになっている <= 文字配列を文字列として利用する事ができる [ポイント] (今まで、「文字列」を関数の引数に指定してきたのと 同じように) 配列名を関数の引数に指定できる。 (なぜか、他の型と異なり..) 配列のメンバーが、関数内と呼び出し側で共有される => 配列名や"〜" は、「ポインター値」を持つ <= 「ポインター値」がいろいろな事をする 見かけ上、引数に対する振る舞いが異なるのはなぜか ? [今日の内容] メモリーモデル メモリーは、セルと呼ばれる小さな記憶装置の集まり 一つセルは、8bit = 1 byte の情報(0〜255=2^8-1)が記録できる 一つ一つのセルには、番地が付けられている C 言語でいう変数の実体は、このセルのあつまり。 char 型の変数は、一つセルに対応している !! 今の言語は、このメモリーに関しては、抽象度が高いので、 !! 意識しなくてもよい !! C 言語はメモリを意識しないといけない言語(中級言語) 「文字列」と呼んでいた "〜" が直接表現しているのは、 "〜" の文字が入っているセルのアドレスの値を表現している 1 を加えると、アドレスが 1 増えて、一つ文字を飛ばした場所を 表現する事になるので、そこから出力すると、先頭の文字が一文字短くなったように見える ここで、「文字列」は、「文字配列」だったので、 文字配列の配列名を引数渡しても同じ事がおきる C 言語の変数と、メモリモデルの関係 C 言語 メモリモデル 変数 セルの集まり 変数名 セルの集まりの先頭のアドレス 変数名の右辺値 セルの内容そのもの 式の中に「変数名」だけを書く => 右辺値を表す # 関数の引数が「式」である事に注意 もし、「左辺値」を必要する場合は、変数の前に「&」を付ける => アドレス値(に相当する値)が取り出される 変数名の左辺値 アドレスを指す 配列 セルの集まり 配列名 セルの先頭の要素のアドレス値 もし、「配列名」だけを、書くと、これは、そのアドレス値となる 配列名は、「定数」 # char a[10]; a[0]='A' は OK だが、 a="abc" は NG !! 変数名と配列名は扱いが異なるのは気持ち悪い !! => 番地を利用する事で、メモリが直接利用可能なのは、大変強力 !! 効率が全然違う !! => 配列名を単独でかいた場合に、番地になるという扱いは、 !! C 言語で効率的なプログラムが書けるようにする仕組み # 代入文 a=a の時、左の a と右の a は、違う意味を持つ # 左側の a は、代入先のアドレスを表し、 # 変数 a の左辺値 # 右側の a は、セルの中身を表している # 変数 a の右辺値 C 言語では、メモリの番地がデータとして扱える & 「左辺値を持つもの」の前につけて、「アドレス値」を取り出す アドレス演算子(ポインター演算子) * 「アドレス値」から、「左辺値を持つもの」に変える 間接参照演算子(ポインター剥ぎ演算子) => この二つは、逆演算子になっている 「a」が変数の時 a == *(&a) 「p」が「アドレス値」の時 p == &(*p) 「a == *(&a)」 &a は値を持つので、関数の引数に渡したり、値として返せる メモリモデル アドレスがある セルを指す C 言語の変数は、変数名がある 記憶領域を指す => 記憶領域を指す「アドレス値」が扱える(表面にでてくる) => 配列名は、「アドレス値」そのもの 演算子 * / & & : 変数からアドレス値 * : アドレス値から変数 互いに、逆変換になっている !! アドレス値もまた「値」である !! => C 言語の中で、操作可能な対象 [いろいろ分かった事] & -- scanf の所ででてきた scanf が、変数の値を変更できる理由は、 scanf にアドレス値を渡していたから cf. int a; scanf ( "%d", &a ); /* キーボードから整数値を入力し、変数 a に代入する */ /* scanf は、引数で渡されたアドレス値と、 * (間接参照演算子)を利用して a の値を 書き換えた */ * -- 「文字列」の所で出てきた 「文字列」は、アドレス値をもっており、 * はアドレス値から、そのセルに対応した変数を作る そして、その変数の(右辺)値が、先頭の文字になっていただけ # なぜ、「文字列」に 1 を加えると、先頭の文字が欠けるのか # => 「文字列」がアドレス値で、1 を加えると、「次の文字から始まる、文字列」のアドレス値になるから