第3回
プログラミングの極意 〜 C言語編
このメールマガジンは、趣味でプログラミングしている方から、プロでプロ グラミングしている方まで、プログラミングのポイントを、理論的背景から 実践的手順まで慎重かつ厳格に伝授するメールマガジンである...。


  極意其の三  『コード化したら配列を活用せよ』  
 


パソコンが賢いわけ。
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄

さて、プログラミングする環境も整ったところで、早速プログラムを 作っていこう。 前回のプログラムは、単に「Hello, World!!」と 表示するだけであったが、今回は、貴方の力で少しコンピュータを 賢くすることにする。

コンピュータは、膨大な計算を行う装置なのだが、単に計算を行うの ではなく、高度なアルゴリズムに基づいた判定も行っている。 ロボット犬 が、飼い主の様子を察知して尻尾を振ったりするのは、内部でコン ピュータが判定を行っているからだ。 実際は、パターンマッチングや 辞書検索など、もっと高度な処理を行っているのだが、判定は、 プログラミングにおいて最も基本的な処理であるといえる。 なぜなら、パターンマッチングや辞書検索でも最終的には、正しい結果 であるものかどうかを判定しているからだ。


判定文の書き方。
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄

判定は、最もベースとなる機能なので、どのプログラミング言語でも 記述することができる。 ここで、C言語での判定文の書き方をおさらいしておく。 C言語では、if 〜 else 文と中括弧 '{', '}' を使って、次のように記述する。

#include  <stdio.h>

void  main()
{
  int  i = 0;   /* 整数型(int)のローカル変数 i を宣言。この記述で変数 i が使えるようになる */

  printf( "数値を入力してください:" );
  scanf( "%d", &i );   /* "%d"は int 型用 */

  if ( i <= 5 ) {
    printf( "i は5以下\n" );
  }
  else if ( i > 10 ) {   /* 必要なければ、このブロックは、記述しなくてもよい。*/
    printf( "i は10より大きい\n" );
  }
  else {  /* それ以外なら */
    printf( "i は6〜9\n" );
  }
}

上の判定を図示すると次のようになる。

文字の判定を行うには次のように行う。

#include  <stdio.h>
#include  <string.h>  /* 文字列の判定関数を使うために必要 */

void  main()
{
  char  string[256];   /* 最大 255文字(256-1)格納可能な文字列変数の宣言 */

  printf( "貴方の名前をローマ字で入力してください:" );
  scanf( "%s", string );   /* "%s"は char[]型用, char[]型のscanfは、stringの前に &は不要 */

  if ( strcmp( string, "taro" ) == 0 ) {  /* 0 の左の == が判定記号 */
    printf( "taro はアホ\n" );
  }
  else {  /* それ以外なら */
    printf( "%s はエライ\n", string );  /* %s は string の内容に置き換わる */
  }
}

更に詳しく知りたい人は、検索サイトで「if文」と入力して検索してみるとよい。 非常に多くヒットするはずだ。

分からないことがあっても、専門用語などのキーワードが分かれば、 インターネットの検索サイトで必ず見つかる。 特にプログラミングに関することを書いているサイトは非常に多いので、 昔に比べて、プログラミングの敷居は低くなったと見ていいだろう。 特に、関数名やクラス名が、プログラミング独特なものであれば 見つかりやすい。


じゃんけんの勝負を判定するには。
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄

プログラム言語が最低限用意している判定文は、数値の大小か、 文字列の大小(ABC順の大小)の判定しかできない。 それ以外の判定をするにはどうしたらいいのだろうか。

実は、文字列の判定も数値の大小によって判定している。 それができるのは、1つ1つの文字が文字コードと 呼ばれる数値に対応しているからだ。 たとえば、'A' は、 0x41だ。 0x41の 0x は16進数であることを表わし、0x41を 10進数にすると 65になる。「16進数」についての詳細は、 検索サイトを調べて欲しい。 同様に、日本語の文字も 対応する文字コードの値が存在する。 つまり、文字列の 判定は、文字コードの数値の大小を判定しているのだ。 そして、文字コードは、ABC順、あいうえお順、漢字の音読み の順に並んでいるので、文字コードの小さい順に並べれば、 ABC 順などにソートすることができるのだ。

では、じゃんけんの勝負の判定は、どのようにすればいいだろうか。

もう、お分かりだろう。 じゃんけんの勝負の判定は、 自分と相手のだした手を比較すればいいので、 グー、チョキ、パーに対応する手コード(数値)を 決めてやればいいのだ。

C言語には、キーワード(識別子)に対応する数値を 設定する機能が備わっている。 それは、#define や、 enum や、const だ。 どれを使ってもいいが、 様々な理由で(理由は割愛)、#define, enum, const の順で使われていることが多い。

#define  GU     0
#define  CHOKI  1
#define  PA     2
enum {
  GU = 0,   /* 最初が 0 のときは = 0 を省略可能 */
  CHOKI,    /* 前の識別子の数値+1なので = 1 を省略 */
  PA        /* 最後の識別子の後にコンマが付けられないコンパイラもある */
};
const int  GU = 0;
const int  CHOKI = 1;
const int  PA = 2;

では、自分の手を入力したら、相手(コンピュータ)の手を ランダムに決めて、勝負の結果を表示するプログラミングを 作ってみよう。 多くの人は次のようになるだろう。

#include  <stdio.h>   /* printf, scanf */
#include  <stdlib.h>  /* rand */
#include  <time.h>    /* time */

/* 手コード */
#define  GU     0
#define  CHOKI  1
#define  PA     2

char*  TeString[] = { "グー", "チョキ", "パー" };
  /* 文字列配列。 手コードから文字列に変換するために使われる */


void  main()
{
  int  human, com;


  /* 手を入力する */
  printf( "じゃんけーん(0=グー、1=チョキ、2=パー)" );
  scanf( "%d", &human );

  srand( (unsigned int)time(NULL) );  /* 時刻で乱数の種を与える */
  com = rand() % 3;  /* 0から2 までランダム */


  /* 手を表示する */
  printf( "あなた=%s, 私=%s\n", TeString[human], TeString[com] );


  /* 判定結果を表示する */
  if ( human == com )  printf( "あいこです。\n" );
  else if ( human == GU ) {
    if ( com == CHOKI )  printf( "あなたの勝ち!\n" );
    else  printf( "私の勝ちです。\n" );   /* com == PA */
  }
  else if ( human == CHOKI ) {
    if ( com == PA )  printf( "あなたの勝ち!\n" );
    else  printf( "私の勝ちです。\n" );   /* com == GU */
  }
  else {   /* human == PA */
    if ( com == GU )  printf( "あなたの勝ち!\n" );
    else  printf( "私の勝ちです。\n" );   /* com == CHOKI */
  }
}


if文だけが判定じゃない。
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄

C言語では、if文の代わりに switch文を使って判定することもできる。 判定結果を表示する部分は次のようになるだろう。

  /* 判定結果を表示する */
  if ( human == com )  printf( "あいこです。\n" );
  switch ( human ) {
    case GU:
      if ( com == CHOKI )  printf( "あなたの勝ち!\n" );
      else  printf( "私の勝ちです。\n" );   /* com == PA */
      break;
    case CHOKI:
      if ( com == PA )  printf( "あなたの勝ち!\n" );
      else  printf( "私の勝ちです。\n" );   /* com == GU */
      break;
    case PA:
      if ( com == GU )  printf( "あなたの勝ち!\n" );
      else  printf( "私の勝ちです。\n" );   /* com == CHOKI */
      break;
  }

いや、私がこの章で言いたかったことは、そんなことじゃない。 if文や switch文などの判定文を「使わないで」判定することができるのだ。 果たしてそんなことができるのだろうか?

このテクニックは、判定文を使わないで判定するため、C言語以外の プログラミング言語でも使うことができるのだが、どんなときでも 使えるわけではない。 その代わり、使えば処理速度の向上も 期待できる。

さて、解説を始めるが、その前に、じゃんけんの勝負の判定を表にまとめてみよう。

A↓、B→グーチョキパー
グーあいこAの勝ちBの勝ち
チョキBの勝ちあいこAの勝ち
パーAの勝ちBの勝ちあいこ

では、この表を、二次元配列と見てプログラミングしてみよう。

#include  <stdio.h>   /* printf, scanf */
#include  <stdlib.h>  /* rand */
#include  <time.h>    /* time */

/* 手コード */
#define  GU     0
#define  CHOKI  1
#define  PA     2

char*  TeString[] = { "グー", "チョキ", "パー" };
  /* 文字列配列。 手コードから文字列に変換するために使われる */


/* 勝負結果コード */
#define  A_WIN  0
#define  B_WIN  1
#define  DRAW   2

int  Judge[3][3] = {     /* 配列番号は、[Aの手][Bの手] */
              /* B: GU    CHOKI     PA */
  /* A:GU */    {  DRAW,  A_WIN,  B_WIN, },
  /*   CHOKI */ { B_WIN,   DRAW,  A_WIN, },
  /*   PA */    { A_WIN,  B_WIN,   DRAW, },
};

char*  JudgeMsg[] = { "あなたの勝ち!", "私の勝ちです。", "あいこです。" };


/* 処理 */
void  main()
{
  int  human, com;


  /* 手を入力する */
  printf( "じゃんけーん(0=グー、1=チョキ、2=パー)" );
  scanf( "%d", &human );

  srand( (unsigned int)time(NULL) );  /* 時刻で乱数の種を与える */
  com = rand() % 3;  /* 0から2 までランダム */


  /* 手を表示する */
  printf( "あなた=%s, 私=%s\n", TeString[human], TeString[com] );


  /* 判定結果を表示する */
  printf( "%s\n", JudgeMsg[ Judge[human][com] ] );
}

配列は、配列番号を使ってランダムアクセスすることができる 特徴がある。 それを応用すれば、配列番号を入力値、 配列の値を判定結果などの出力値と見ることができるのだ。 このテクニックは、入力値が整数で連続していれば、使うことができる。 もし、3から始まるときは、マイナス3をした配列番号にすればいいのだ。

配列を使うことは、if や switch では表現できないような、 表形式になることが多く、データのみを扱うため、 プログラム・ミスが減るようになる。 更に、書き方の違いだけではなく、処理速度もこちらのほうが速い。 コード化したとき(対応する数値を与えたとき)は、 配列が使えないかを考えるとよい。


  極意其の三  『コード化したら配列を活用せよ』  
 


このメールマガジンの図は、 SVGCats を使って作成しました。
表示するには、 Adboe の SVG のページ からプラグインをダウンロードしてください。


前回の補足。
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄

C:\borland\bcc55\Bin\bcc32.cfg や C:\borland\bcc55\Bin\ilink32.cfg をメモ帳で保存するときは、ファイルの種類を「すべてのファイル」に してください。 そうしないと、勝手に .txt という拡張子がついて しまって、コンパイルに失敗します。アイコンがメモ帳になっていたら .txt が付いています。「すべてのファイル」にして保存してください。

Autoexec.bat は、隠しファイルになっているので、コントロール パネルのフォルダオプションで、隠しファイルを表示するように 設定しないと表示されません。 表示された Autoexec.bat ファイル を右クリックして「編集」を選ぶことで編集することができます。 最終行に、set PATH=C:\borland\bcc55\Bin;%PATH% と追加記述して 保存します。

コンパイラが正しくインストールされたかどうかのチェックをするとき に表示されるメッセージは、スクロールアウトしてしまうため、 前回のメールマガジンで説明したものの一部しか表示されません。 それでも、正しくインストールされています。


______________________________
▼ Sage Plaisir 21 commercial message       www.sage-p.com
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
このメールマガジンは、 ソフトウェア・デザイン館 Sage Plaisir 21
から発信しています。 オブジェクト指向やオープンソース・
ライブラリなど、プログラミングに関する情報を提供しています。

「プログラミングの極意 〜 C言語編」では、創刊を記念して、
ささやかな懸賞を始めました。 読者登録したアドレスを使って
サンプルページから応募できます。
http://www.sage-p.com/ml-samp2.htm

Sage Plaisir 21 から発行しているメールマガジンでは、広告掲載の
募集を開始しました。あなたもワンコイン広告をしてみませんか?
http://www.sage-p.com/ml2/ad.htm

SVG Cats が、10/29(火)発売の DOS/V POWER REPORT 通巻100号
記念号の「今月の一押しソフト」に選ばれました!!本屋さんで
見かけたら買ってくださいね。

SVG Cats が、WWW の標準化団体 W3C のニュースで扱われていました!
http://www.w3.org/Graphics/SVG/Overview.htm8
______________________________



□∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞□
 最後までお読みいただきありがとうございます。
 バックナンバーの参照または購読の解除は、こちらへ。
 広告掲載をご希望の方はこちらへどうぞ。

 All Text composed by T's-Neko 2002
         ご意見、ご要望は neko@manbow.com まで。
     ソフトウェア・デザイン館 Sage Plaisir 21
         http://www.sage-p.com/
□∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞□