const hoge* xとポインタを宣言した場合
前提:
typedef struct hoge {
int i;
} hoge;
とhoge型を宣言しておく
①const hoge* xとポインタを宣言した場合
(xの型がconst hoge*)
xの住所はいくらでも変えられる。
(x = 1000, x = 1001, x = 1002, …という感じに)
!!*xはconst hoge型
const hoge型というのは、中身を書き換えてはいけないhoge型
(hogeなんだけど、中身を書き換えちゃならない)
const hogeは構造体なので…構造体の中身のメンバいずれも書き換えてはならない、ということ。!!
とある構造体の名前.メンバ名 = とある構造体を指すポインタ -> メンバ名
(*foo).bar = foo->bar。
この二つはお互いに入れ替え可能、コンパイラはこの二つを全く区別しない。
書くのが速いため(だけに)後者を使うことが多い。
実は、構造体を扱おうとするとき、構造体の名前(*foo)よりも構造体を指すポインタ(foo)を使用することが多い、ことによる。
!!つづき
(*x).i = 42; // これはできない(コンパイルエラー)
x -> iを読み出すことはできるが、
x -> i = 42などと書き込むことはできない。!!
②ポインタを宣言するということ
は、ポインタの分(=アドレスを入れる分)のメモリは確保できる。しかし、これだけではアドレスの指す先はない…つまり、家の表札だけあって家は無い(土地すら無い)状態。
だから、
ポインタの宣言→malloc or 先に別のところで変数を宣言し、モノ(家)を作って
→mallocならそのallocateしたmemoryにポインタの指したい値を入れれば良いし、
後者だったら宣言した変数のアドレスを、ポインタの中に入れればok。
後者の例:
const hoge* x; // const hoge*型のポインタxを宣言
hoge y; // hoge型の変数yを宣言
y.i = 42; // hoge型変数yの中身を入れる
x = &y; // hoge型変数yぶんのメモリは確保されているので、yのアドレスをポインタxに代入
ちなみに...
y.i = 100; の変更→可能
x -> i = 100; の変更→エラー
だが...
y.i = 100; と変更すると、
x = &yのためx -> iの中身も100に変化する(!!)
const hoge型*xは、xの側からは変更ができない(定数である)のだが、
yの側からはいくらでも変えられてしまうのである...裏の手口みたいだな、なんじゃこりゃ(余り使わないほうが良いらしい)。