4月1日 情報処理技術者試験受験票がこうしろう宛に郵送されて来た。年齢制限がなく過去に中学生の合格者も実際にいる試験なのであるが,本当に中学2年になったばかりのこうしろうが受けてもいいものだろうかと迷いもあった。しかし受験票には試験区分「基本情報技術」,生年月日「1988年09月15日」とキッチリ印刷されている。見事にオープンな試験である。さあ,あとは受験票に写真を貼って,試験会場である富山大学工学部に行くだけと言いたいところであるが,プログラミングの勉強がまだ残っていた。午後問題ではプログラムの作成能力も問われる。プログラム言語はC言語,COBOL,Java,アセンブラからの択一である。

 MindStormsで作ったロボットを動かすNQC(Not Quite C=完全ではないC言語)でプログラミングをかじったこうしろうは,当然C言語を選択する。時折,日経ソフトウエア誌に丸山竜也さんが連載していた『ゼロから学ぶC/C++言語』を読み,サンプルプログラムを打ち込んでBorlandC/C++コンパイラでコンパイルし,少しずつC言語も勉強していたこうしろうであるが,自分で勝手にプログラムを組むというレベルには至っていない。そういう訳で,言語の勉強にしては付け焼刃な感は否めないが,こうしろうは現在C言語の勉強の真っ最中である。

 C言語の過去問題を眺めてみると配列,ポインタ,文字列操作,構造体,ファイル操作に関する問題が多い。配列にしても,構造体,文字列操作にしてもポインタに密接に関係している。C言語が身に付くか否かはポインタが理解できるかどうかにかかっているので,ポインタの扱いに慣れることが重要である。それから代表的な関数,ファイルやキーボードからデータを入力するfgetsやその逆に出力を行うfputs,文字列関数で言えばstrcpyやstrlen,strncmp,strcatなどの知っていて当たり前の関数を覚えることも必要である。

 こうしろうは『はじめてC言語』という初心者向けの入門書で基礎をおさらいした後,情報処理技術者試験『実戦問題』で練習問題を解いてみていた。

 「なんか,わからん記号が出てきた」と質問に来たのが次のプログラムである。



#include <stdio.h>
#define N_MAX 32
#define A_MAX 64
#define P_MAX 16
#define OWARI "xxxx"
#define M_MAX 100

  [  a  ]  {
           char name[N_MAX+1];
           char addr[A_MAX+1];
           char phone[P_MAX+1];
          } ADR;

main( void )
{
  FILE *fp;
  [ b ] member[100], *ptr, *str;
  char name[N_MAX+1];
  int len;
  
  fp=fopen( "MEMBER.ADR", "r");
  if ( fp == NULL ) exit(1);

  ptr = [ c ];
  while( fgets( [ d ]name, N_MAX, fp ) != NULL ) {
    fgets([ d ]addr, A_MAX, fp );
    fgets([ d ]phone, P_MAX, fp );
    ptr++;
  }
  fgets( name, N_MAX, stdin );
  while( strncmp( name, OWARI, 4 ) != 0 ) {
    len = strlen( name ) - 1;
    str = member;
    while( str < [ e ] ) {
      if ( strncmp( str->name, name, len ) == 0 ) {
        fputs( str->name, stdout );
        fputs( str->phone, stdout );
      }
      [ f ];
    }
    fgets( name, N_MAX, stdin );
  }
  fclose( fp );
}


 a,b,c,d,e,fに入る答えを用意された選択肢から選べという問題である。プログラムの概要はと言うと,MEMBER.ADRというファイルをfopen関数でオープンし,fgets関数で読み取った名前,住所,電話番号を配列memberにストアしていく。次にfgets関数の引数にstdinを指定し,キーボードから名前を入力させる。そして入力された名前とmember配列にストアした名前の一部が一致するデータの名前,電話番号をfputs関数に引数stdoutを指定することで画面に表示する。キーボードから入力された文字数分だけ一致するかどうか調べるためにstrncmpを使っている。配列の操作にはポインタを使う。

 高級な寄せ鍋のように,ソースコードの量は決して多くないが,C言語の大事なネタを全て仕込んでいる。見事な問題である。

 [ a ]には, 構造体を定義するtypedef structが入る。[ b ]はADRであり,ADR型の配列memberとADR型のポインタ変数*ptrと*strを定義する。[ c ]には,memberが入る。配列名はその配列の先頭アドレスを指すので,以降ptrで配列を順に操作していける。

 こうしろうがわからなかったのが[ d ] に入るptr->の->である。このアロー演算子が何を意味するのかわからなかったらしい。構造体のメンバーをポインタから参照する時はポインタ->メンバー名(ptr->name)という書き方ができるのである。アロー演算子がないともっとややこしい書き方,(*ptr).nameをしなくてはいけないのが,アロー演算子のお陰で簡潔に表現できるのだ。

 [ e ]にはptr,[ f ]にはstr++が入り,member配列にストアしたデータの件数分,入力された名前に一致するデータがないか,繰り返し比較が行われる。