わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

「ポインタの裏話」を読んで

楽しく読みました.自分の授業に取り入れたいところもあるなあと感じつつ,何箇所か,これまで教えてきたことと異なっていますので,手短に記録を残すことにします.
まず,配列とポインタの違いを明確にしていないところで,引っかかりを覚えました.

  int a[2];
  a[0] = 3;

と書いていいけれども,

  int *p;
  p[0] = 3; /* もしくは *p = 3; */

と書いてはいけません.
実際のところ,配列とポインタとでは,メモリ内部での表現が異なります.
そしてこのような,初期化(指し示す先を設定)していないポインタ変数を使って,参照して書き込もうとし,実行時エラー(segmentation fault)が起こるというのは,C言語を学ぶ授業が過ぎ,2年向けの演習の中でも,巡回をしているとよく見かけるのです.
2番目に,文字列の説明に際して,文字列リテラルが一切出て来ないのに戸惑いました.その中でも最も気になったのが

実は”"で文字列を
使う度に,裏で文字
配列が生成される
(p.69)

という文です.ご利用の環境はそうなっている,ということなのでしょうか.JIS X 3010:2003を読むと,文字列リテラルは静的記憶域期間をもつことが,6.4.5 (p.45)に記されていまして,「使う度に…生成される」と矛盾するのです.
なお,配列の初期化を除いて,文字列リテラルに対応づけられる配列を「書き換えてはいけない」ことにも,注意を促したいと思います*1
最後に,関数の仮引数として,配列を書く事例が見当たらないのも,残念な思いです.というのも,仮引数のところに配列の形で変数を書いても,その実体はポインタとなります.関数内で,その配列の要素数を得ようとするとき,「sizeof(変数) / sizeof(変数[0])」が使えませんので,要素数も引数にして受け渡しする,オブジェクト形式マクロなどの定数を参照する,といった工夫が不可欠です.
文字列の受け渡しなら,仮引数はポインタ(char *)にするのが普通でしょうが,多次元配列を関数呼び出しでやりとりするとき,ポインタで書くと煩わしくなり,配列形式で書くのが素直なやり方です.


批判ばかりというのも何なので,一つ情報提供を.尊敬する学科の教員が,学生向けに,ポインタとその応用についての文書を作成されています.

*1:理由は少々長くなるので,脚注記法にします.JIS X 3010だとp.46に「プログラムがこれらの配列を変更しようとした場合、その動作は未定義とする。」とあります.『C言語によるプログラミング―スーパーリファレンス編』p.197では,「char numstr[] = "1234567";」「char *nump = "abcdefg";」の違いを示しながら,「プログラム中に配列の初期化子以外の形で記述された文字列リテラルは,変更可能な記憶域(たとえば,ROM:Read Only Memory)に格納される可能性もあるからです。」と書かれています.