変数の次元はできるだけ小さくしよう

お隣の建物にいる研究室の友人から相談を受ける.どうやら実験でC言語のプログラムを書いているみたいだけど,設計上の問題やら実装上の問題が発生して困っているらしい.

研究内容と実験内容を聞いて,Cで書く理由はまったくないなと思ったので「なんでCで書いてるの?」と聞いたら,「先輩がみんなC (not C++)で書いてるから」「今からほかの言語を覚えるなんて耐えられない」と返ってきた.

配列と基本的な演算ができて動くプログラムは作れているし,関数の使い方(作り方)も最近覚えたらしいので,別に無理に新しい言語を勧めることもないなと判断して(Pythonをお勧めしたかったけどな)C (not C++)の実装を一緒に考えてきた.


プログラムを書いた経験が少ないと「自分の書いている書き方はこれで合っているのだろうか」みたいな不安があるらしく,もっといい方法ある?みたいな感じのことを何度か聞かれたが,基本的には動けばいいから問題ないよと答えておいた.初心者がこんな方針で書いたプログラムを公開するからPHPがどうのという話で盛り上がるんだろうけど,プログラミング初心者はまずは動かすことを一番に考えるのが重要だと思う.


他には配列が5次元になってしまってわけわからないと言っていたので,構造体を教えた上で,不必要な変数の分類をやめて一つにまとめてしまうのがいいよと伝えた.どういうことかというと,たとえば以下のようなキーボードの各キーに関する情報を配列に入れておくとすると,普通は30個の配列を用意してひとまとめにしておくと思う.

Q W E R T Y U I O P
A S D F G H H J K L
Z X C V B N M , . /
int key[30];

だけど,変数にアクセスするときに「左手」の「小指」の「上段」のキーに関する情報を知りたいという操作が頻繁にあるとしたら下のように宣言するのもありだ.そして,単純に下のようにすると配列の次元数は増えていく.

//     手/指/段
int key[2][5][3];

次元数が増えるとその変数の意味が分かりにくくなるという問題以外にも,初めに実現しようとした操作以外は面倒になるという問題がある.単純にすべてのキーについて何か値を代入するような場合でも以下のように大きな違いが出てしまう.

int key[30];
for(int i=0; i<30; i++){
  key[i] = ...
}
int key[2][5][3];
for(int i=0; i<2; i++){
  for(int j=0; j<5; j++){
    for(int k=0; k<3; k++){
      key[i][j][k] = ...
    }
  }
}

データ構造を特定の目的のために複雑化するとその他の操作で必要な手続きが増えてしまうのだ.そのため,プリミティブなデータについては上記のような複雑にしないで,できるだけ単純な形にしておくのが良いと思う.それで,もし「左手」の「小指」の「上段」の…といった操作が必要なのであれば,それを実現する関数なりを用意する方がよいのだと思う.

こういう話は普通にプログラム関係の本に載ってそうだけど読んだことない.文章にしてみたおかげで今まで感覚的に書いていたことが少しすっきりした気がする.