第8回 応用1(6月6日)

今日の課題

複数のカードを配列に格納する。カードには、名前やドライバーナンバーの他に、画像データを記憶させる。複数のカードから、必要なものを抽出した結果を別の配列に、リンクとして格納する。

■ 画像付きネームカード

画像データを格納するために、namecard.h と namecard.c を変更しよう。

まず、ネームカードの構造体を変更する:
typedef struct {
  char       name[NAME_LEN];
  int        age;
  int        number;
  char       *file;
  Array2dInt *img;
} NameCard;

これに関連して、次の追加をしよう。

■ 表示用の配列

複数の画像ファイル名が、コマンドライン引数として与えられるものとする。このファイル名に基づき、ネームカードを生成する。同時に、画像ファイルもロードする。
(例)
> ./a.out PGM/01_Kimi_Raikkonen.pgm PGM/02_Felipe_Massa.pgm PGM/03_Nick_Heidfeld.pgm PGM/04_Robert_Kubica.pgm

上記のように実行したとき、main 関数では、4つの NameCard * で構成される配列変数を作成し、ドライバー名、ドライバー番号、画像ファイル名を格納し、画像データをロードする。

次に、特定のドライバーを抽出した結果を残すために、main 関数では、NameCard * の配列のインデクス番号(int)を要素とする配列変数を作る。

今回は、練習として、ドライバー番号が奇数の NameCard のインデクス番号を後者の配列変数に格納する。
(例)
int main( int argc, char **argv )
{
  NameCard **ncarray, *nc;
  int *result, i, j, num, sz;
  char name[NAME_LEN], imgfile[10];

  sz = argc - 1;  // ドライバーの人数
  ncarray = 引数のドライバーの人数ぶんだけ NameCard * を malloc
  result = ncarray の配列番号 int を格納するための配列を malloc
  // ncarray にロード ---------------------------------------
  for( i = 1, j = 0; i < argc; i += 1, j += 1 ){
    nc = nc_open();
    ncarray[j] = nc;
    argv[i] を解析し、ドライバー番号num, 名前 name を得る。
    ネームカード nc に代入する。
    画像ファイル名を nc に代入する。
    画像ファイルをロードする。
  }
  // 抽出処理 ------------------------------------------------
  for( i = 0, j = 0; i < size; i += 1 )
    if( ncarray の i 番目のドライバー番号が奇数かどうか検査 )
      result[j++] = i;
  // 出力 ----------------------------------------------------
  for( i = 0; i < j; i += 1 )
    nc = ncarray[result[i]];
    printf("%d\t%s\t[%s]\n",
	   nc_get_driver_number( nc ),
	   nc_get_name( nc ),
	   nc_get_filename( nc ));
    snprintf( imgfile, 10, "tmp%d.pgm", nc_get_driver_number( nc ) );
    nc_save_image( nc, imgfile );
  }
  return 0;
}

引数 argv の解析ルーチンの例
int scan_argument( char *line, int *num, char *name, int lmt )
{
  char tmp[3], *p, *q;
  int i, len;

  // 末尾から「/」の手前までをファイル名として抽出する
  len = strlen( line );
  p = &line[len - 1];
  for( ; len > 0; len -= 1, p -= 1 ){
    if( *p == '/' ){
      p += 1;
      break;
    }
  }
  // 数値部分を抽出する ------------------------------------
  for( i = 0; i < 2; i += 1, p += 1 ) {
    if( !isdigit(*p) )
      return 0;
    tmp[i] = *p;
  }
  if( *p != '_' )
    return 0;
  tmp[2] = '\0';
  *num = atoi( tmp );
  p += 1;
  // 名前部分を抽出する(拡張子を含めない) ------------------
  lmt -= 1;
  for( i = 0, q = name; i < lmt; i += 1, p += 1, q += 1 )
    if( *p == '\0' || *p == '.' )
      break;
    else if( *p == '_' )
      *q = ' ';
    else
      *q = *p;
  *q = '\0';

  return 1;
}


2008.6.4 by tokuhisa