演習(その3)の解答例: 問題2 - しりとり

単語(文字列)を順次入力して, それが前の単語の末尾の文字から始まっているかどうかを 調べ続けるプログラムを作成する.

レベル 1

同じ単語を何度も使ってよい
#include <stdio.h>

main()
{
  char word[80];
  char last_tail;		/* 前回の単語の最後の文字 */
  int ok = 1;			/* うまくいっているかどうか */
  int i;

  printf("word? ");
  scanf("%s", word);		/* 最初の単語を読み込み */
  while(ok){
    for(i=0; word[i] != '\0'; i++); /* i は単語の終端の 0 の添字 */
    last_tail = word[i-1];	/* 単語の最後の文字の取り出し */
    printf("word? ");
    scanf("%s", word);		/* 二回目以降の単語の読み込み */
    ok = (word[0] == last_tail); /* 今回の先頭 = 前回の最後 ? */
  }
  printf("failed\n");
}
最初の単語だけはループの外で入力している点に注意.

レベル 2

同じ単語は一度しか使えない
#include <stdio.h>

main()
{
  char word[80];
  char words[100][80];		/* これまでに使った単語を記憶する */
  int nwords;			/* 記憶してある単語数 */
  char last_tail;		/* 前回の単語の最後の文字 */
  int ok = 1;			/* うまくいってるか */
  int i, j;

  nwords = 0;
  printf("word? ");
  scanf("%s", word);		/* 最初の単語の読み込み */
  while(ok){
    for(i=0; word[i] != '\0'; i++){ /* 新規の単語として記憶する */
      words[nwords][i] = word[i];
    }
    words[nwords][i] = '\0';
    last_tail = word[i-1];	/* 最後の文字もとっておく */
    nwords++;			/* 単語数をふやす */

    printf("word? ");		/* 二回目以降の単語の読み込み */
    scanf("%s", word);
    if(word[0] != last_tail){	/* 前回末尾と先頭のチェック */
      ok = 0;
    }
    /* ここからが既出かどうかのチェック */
    for(j=0; j<nwords; j++){	/* 記憶してある単語を順にたどって */
      for(i=0; word[i] != '\0'; i++){ /* 各文字を比較していく */
	if(word[i] != words[j][i]) break; /* 違ってたら合格 */
      }
      /* 同じ場合にも違う場合にもここに出てくる */
      if(word[i] == words[j][i]){/* 最終的に同じだったかを判定 */
	ok = 0;
	break;			/* 既出なら, 記憶単語のループを途中脱出 */
      }
    }
  }
  printf("failed\n");
}
ループの最後の既出かどうかのチェックがやや美しくない. 内側の for 文から break で抜け出した時に, その for を正常に完了した時と同じ場所に出てきてしまう. 上のプログラムでは, わざわざそのあとでもう一度比較を行なっている.

文字列比較のライブラリ関数を使えば, ずっときれいに書ける. (設問の趣旨からはすこし外れるが)

    /* ここからが既出かどうかのチェック */
    for(j=0; j<nwords; j++){	/* 記憶してある単語を順にたどって */
      if(strcmp(word, words[j]) == 0){ /* 同じ単語があった */
	ok = 0;
	break;			/* 既出なら, 記憶単語のループを途中脱出 */
      }
    }

prev index next