わさっきhb

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

配列・ポインタ指導の分岐点

木曜5限の演習室,2年生向けCの復習科目*1では,今週までの授業で4週かけて,配列・ポインタを再確認します.課題は昨年度と大差なし,と言いつつも,例題プログラムや問題文を少しずつ変更しながら,理解を深められるよう,試みています.
そんな中で,頭の中で思い描いている,「教える人によって違うところ」を,並べてみます.

1. 規格か,実体か

配列やポインタの違い,またその使いどころについて,「規格に基づいて説明するスタイル」と,「メモリの状態を使って展開するスタイル」があるように思います.
規格に強く依拠しているのは,これまでの私の授業です.自分のに限らず,その種の文章を見つけるためのチェックポイントは,「文字列リテラル」でしょう.「文字列」と区別して解説していれば,当たりです.
別の見極め方として,箱モデルで配列やポインタなどを表現しているたとき,それぞれに具体的なアドレスが割り振られていないのも,挙げていいでしょう.
実体(メモリにどのように割り付けられるか)を強く意識した解説文書は,本日の別エントリで2つ,紹介したとおりです.

2. 配列変数・ポインタ変数と言うか言わないか

K&Rでは,配列(array)は変数であることを明示していないのに対し,ポインタ(pointer)はその定義の中にvariableと書いています.
配列を変数とみなした場合,a = b;といった形での代入ができない,という問題点もあります.
それに対して,「配列」「ポインタ」といった技法の総称と区別するために,個別の変数のことを「配列変数」「ポインタ変数」と呼ぶ向きもあります.
この点については私は,「配列変数」「ポインタ変数」と書く方式を採用し,受講生にも一般的な用法でないことを含めて,伝えています.その際,変数ではないポインタの値は「ポインタ値」と書きます.char *p = "abc";と書いたとき,p + 2がポインタ値の一つです*2.配列とポインタの関係は,「いくつかの例外を除き,式の中の配列変数名は,その先頭を指し示すポインタ値として評価される」と表せます.

3. コマンドライン引数を用いて入力を獲得するか

「int main(int argc, char *argv[])」のことです.
入力をどのように獲得する(よう,プログラムを書ければいい)かというのは,厄介な話の一つです.私の授業では,ファイル入出力の前振りで

  • プログラム内に値を書く(ハードコード)
  • 標準入力から獲得する(scanfなど)
  • コマンドライン引数から獲得する(argc, argvなど)
  • ファイルを読み出して獲得する(fopenなど)

を平等に取り上げています.
とはいえ個人的な思いとしては,プログラムの動作の再現可能性を重視しています.そのため,標準入力からの獲得は,「まあこういう方法もあるんだよ」という申し訳程度*3としています.他の3つは,その特徴や制約に注意しつつ,バランスよく説明し,サンプルプログラムを示すのがいいという信念に至っています.
書籍やWebの情報を見ていると,コマンドライン引数からの獲得を活用しているところが少ないように感じます.「ポインタのポインタ」「文字列の配列・ポインタ」についての知識を必要とする点や,統合開発環境では実行のたびにコマンドライン引数を変更するのに手間がかかる点が,デメリットとして挙げられます.

4. 自作関数を,いつ学習するか

これもまた二者対立ではなく,いくつか選択肢を設けることができます.

  • 自作関数を,配列より前に学習するか
  • 自作関数を,配列のあと,ポインタより前に学習するか
  • 自作関数を,ポインタよりあとで学習するか

学習者の理解のしやすさとして,どれが最善というものはなさそうなのですが,私の授業では,ポインタよりあとで解説します.というのも,「配列」「ポインタ」「関数」「変数(有効範囲,生存期間)」「再帰」あたりを,C文法理解の第2段階と位置づけて,授業を組み立てているからです.
それらを貫くキーワードは,規格の側から言うと「オブジェクト」であり,実用上は「変数などの値が,メモリにどのように格納されるか」となります.

*1:3人の教員で担当しており,加えて今年度も,2名のティーチングアシスタントの協力を得て,実施しています.

*2:「配列値」という言葉はさすがに使いませんが,例えば「int a[2][3];」や「void func(int a[2][3]) {...}」と書いたときのa[0]が該当するかもしれません.型名でいうと,a[0]は,int[3]型となります.なお,2つの宣言のうち前者のaはint[2][3]型の配列,後者のaはint(*)[3]型のポインタです.

*3:プログラムがうまく動かないという相談を受けたとき,ソースコードが原因なのか,入力値が不適切なのかといった,問題の切り分けをしたいことがあります.標準入力を用いるのは,他の3つと比べて,苦労するのです.