コーディング実技試験 問題と解答解説

[1](山田クラス)

次の (1), (2), (3) に指定されたとおりにプログラムを作れ.
(1) 国語,数学,英語の3科目の成績を一人分だけまとめた構造体(整数型メンバ kokugo, sugaku, eigo を持つ)を作り,それをseiseki_t という名前の型として定義せよ.
(2) seiseki_t 型の引数を1つとり,その3科目の平均点を返す関数 double heikinten(seiseki_t s) を作れ.
(3) 3科目の成績を5人分キーボードから入力し,それを seiseki_t s[5] という配列に入れる.それらの中で,平均点が60点以上の人の3科目の成績を表示する.以上のことをするプログラムを作れ.
実行例
50 50 70 20 80 90 80 70 50 60 60 70 30 80 50
20 80 90
80 70 50
60 60 70

#include <stdio.h>
#define NUM 5

typedef struct {
  int kokugo;
  int sugaku;
  int eigo;
} seiseki_t;

double heikinten(seiseki_t s)
{
  return (s.kokugo + s.sugaku + s.eigo) / 3.0;
}

int main()
{
  seiseki_t s[NUM];
  int i;

  for ( i = 0; i < NUM; i++ ) {
    scanf("%d%d%d", &s[i].kokugo, &s[i].sugaku, &s[i].eigo);
  }
  
  for ( i = 0; i < NUM; i++ ) {
    if ( heikinten(s[i]) >= 60 ) {
      printf("%d %d %d\n", s[i].kokugo, s[i].sugaku, s[i].eigo);
    }
  }
  return 0;
}

注意する点は、関数 heikinten 中の部分を (s.kokugo + s.sugaku + s.eigo) / 3 という式にすると 整数/整数となり、結果が整数値(小数点以下切り捨て)になってしまうことである.浮動小数点で計算を 行わせるため、 / 3.0 とする必要がある.

[1](北川クラス)

次の (1), (2), (3) に指定されたとおりにプログラムを作れ.
(1) 3次元ベクトルを表す構造体(3つの成分を表す double 型のメンバ x, y, z をもっている)を作り、それを vector_t という型名として定義せよ。
(2) vector_t 型の引数を1つとり,それが表すベクトルの長さ(大きさ)を返す関数 double vector_length(vector_t v) を作れ。(ベクトルの長さは成分の2乗の和の平方根)
(3) 3次元ベクトル5個分の成分(15個の実数値)をキーボードから入力し,それらを vector_t v[5] という配列に入れる.それらの中で,長さが 10 を超えるものだけを表示する.以上のことをするプログラムを作れ.(ヒント: scanf を用いて double 型の数値を読み込むための書式文字列は "%lf" である.)
実行例
5.0 -4.0 7.0 -3.0 7.0 8.0 2.0 7.0 3.0 4.0 0.0 -4.0 9.0 -3.0 6.0
-3.0 7.0 8.0
9.0 -3.0 6.0

#include <stdio.h>
#include <math.h>
#define NUM 5

typedef struct {
  double x;
  double y;
  double z;
} vector_t;

double vector_length(vector_t v)
{
  return sqrt( v.x * v.x + v.y * v.y + v.z * v.z );
}

int main()
{
  vector_t v[NUM];
  int i;

  for ( i = 0 ;  i < NUM; i++ ) {
    scanf("%lf%lf%lf", &v[i].x, &v[i].y, &v[i].z);
  }
  for ( i = 0; i < NUM; i++ ) {
    if ( vector_length(v[i]) > 10 ) {
      printf("%f %f %f\n", v[i].x, v[i].y, v[i].z);
    }
  }
  return 0;
}

数学関数 sqrt を用いているので,プログラム先頭でヘッダファイル math.h を読み込み, さらに,コンパイル時に -lm のリンクオプションを付けてコンパイルする必要がある.

[2](山田クラス)

文字列 s 中の文字 c の個数を返す関数 int count_char(char s[], char c) を作り,それを用いたプログラムを一つ作成せよ.
例: count_char(“abcdeabc”, 'b') の返す値は 2

#include <stdio.h>

int count_char(char s[], char c)
{
  int i, n = 0;

  for (i = 0; s[i] != '\0'; i++) {
    if (s[i] == c) {
      n++;
    }
  }
  return n;
}

int main()
{
  int n;

  n = count_char("abcdeabc", 'b');
  printf("%d\n", n);
}

[2](北川クラス)

文字列 s 中にある文字 c の場所をその添字で返す関数 int position(char s[], char c) を作り,それを用いたプログラムを一つ作成せよ.ただし,s 中に c が複数個あるときには最初のもの(添字が一番小さいもの)の添字を,また c がないときには -1 を返すものとする.
例 position(“abcdabc”, 'b') が返す値は 1

#include <stdio.h>

int position(char s[], char c)
{
  int i, n = 0;

  for (i = 0; s[i] != '\0'; i++) {
    if (s[i] == c) {
      return i;
    }
  }
  return -1;
}

int main()
{
  int p;

  p = position("abcdeabc", 'b');
  printf("%d\n", p);
}

[3](山田クラス)

cos(1.0), cos(2.0), ..., cos(10.0) の10個の数値の中で最大の値のものを表示するプログラムを作れ.

#include <stdio.h>
#include <math.h>

int main()
{
  double x, max;

  max = cos(1.0);
  for ( x = 2.0; x <= 10.0; x += 1.0) {
    if ( max < cos(x) ) max = cos(x);
  }
  printf("%f\n", max);
  return 0;
}

[3](北川クラス)

sin(1.0), sin(2.0), ..., sin(10.0) の10個の数値の中で最大の値のものを表示するプログラムを作れ.

#include <stdio.h>
#include <math.h>

int main()
{
  double x, max;

  max = sin(1.0);
  for ( x = 2.0; x <= 10.0; x += 1.0) {
    if ( max < sin(x) ) max = sin(x);
  }
  printf("%f\n", max);
  return 0;
}

[4]

1以上13以下の整数値を5個キーボードから読み込み,それがポーカーのどの役にあたっているかを判別して,”no pair”, "one pair”, “two pair”, “three card”, “four card”, “full house”, “straight” のいずれかを表示する.これを繰り返すプログラムを作れ.ただし,範囲外の数値が入力されると終了するものとする.(注意: 10, 11, 12, 13, 1 はストレートであるが, 11, 12, 13, 1, 2 や 12, 13, 1, 2, 3 や 13, 1, 2, 3, 4はストレートではない.フルハウスはワンペアとスリーカードとが合わさったものである.)
実行例
7 4 3 1 10
no pair
3 5 8 5 11
one pair
4 8 6 4 8
two pair
8 7 5 7 7
three card
7 2 7 7 7
four card
4 9 4 9 9
full house
7 4 8 5 6
straight
0 0 0 0 0

問題に不備があったので次の一文を追加する.入力された 5 個の整数値がすべて同じ数値であるときには,そのまま終了する.(ファイブカードはない)

次のプログラムは,読み込んだ数値 card[0], ..., card[4] の値の中に,j という値が何個あるかを数えて cnt[j] に入れることから始める.

この配列を用いることで,役の判断が簡単になる.たとえば,読み込んだ値が 6, 3, 6, 6, 7 の場合, cnt[] の値は次のようになり,その役がスリーカードであることが分かる.

012345678910111213
00010030100000
#include <stdio.h>

int main()
{
  int card[5];     /* 読み込んだ値が入る */
  int cnt[14];     /* 読み込んだ値で 1, 2, 3, ..., 13 に等しいものの個数が入る */
  int i;           /* card[i] の添字 */
  int j;           /* cnt[j] の添字 */
  int max1, max2;  /* cnt[] の要素の値の最大値と2番目の最大値 */
  int p;           /* cnt[13], cnt[12], ... の中で値 1 であるものの最初(最大)の添字 */
  int q;           /* cnt[p-1], cnt[p-2], ... の中で値が 0 であるものの最初(最大)の添字 */
  
  while (1) {
    for (i = 0; i < 5; i++) {
      scanf("%d", &card[i]);             /* 整数値の読み込み */
    }
    for (i = 0; i < 5; i++) {
      if (card[i] < 1 || 13 < card[i]) 
        return 0;                        /* 値が範囲外のときは終了 */
    }
    for (j = 0; j <= 13; j++) {
      cnt[j] = 0;                        /* cnt[] をすべて 0 に初期化( cnt[0] は q を求めるときの番兵となる) */
    }
    for (i = 0; i < 5; i++) {   
      cnt[card[i]] ++;                   /* card[0], ..., card[4] の値の中に,j という値が何個あるかを数えて cnt[j] に入れる */
    }
    max1 = max2 = 0;
    for (j = 1; j <= 13; j++) {
      if (max1 < cnt[j]) {               /* cnt[j] が最大値よりも大きいときは */
        max2 = max1;                     /* 最大値が2番目の最大値になる */
        max1 = cnt[j];                   /* 最大値がcnt[j] になる */
      } else if (max2 < cnt[j]) {        /* そうじゃなくて,2番目の最大値よりも大きいときは */
        max2 = cnt[j];                   /* 2番目の最大値がcnt[j]になる */
      }
    }                                    /* max1には同じカードの最大枚数,max2にはその次の最大枚数が入る. */
    switch (max1) {                      /* 同一カードの最大枚数が */
    case 5:                /*   5のときには */
      return 0;                          /*     終了(ファイブカードは考慮しない)*/
    case 4:                              /*   4のときには */
      printf("four card\n");             /*     フォーカード */
      break;
    case 3:                              /*   3のときには */
      if (max2 == 2) {                   /*     2番目の最大枚数が 2 ならば */
        printf("full house\n");          /*        フルハウス */
      } else {                           /*     そうでなければ */
        printf("three card\n");          /*       スリーカード */
      }
      break;
    case 2:                              /*   2のときには */
      if (max2 == 2) {                   /*     2番目の最大枚数が 2 ならば */
        printf("two pair\n");            /*        ツーペア */
      } else {                           /*     そうでなければ */
        printf("one pair\n");            /*        ワンペア */
      }
      break;
    case 1:                              /*   1のときには */
      for (p = 13; cnt[p] == 0; p--) ;         /* cnt[13], cnt[12], ... の中で最初に 1 であるものを探す */
      for (q = p; cnt[q] == 1; q--) ;          /* cnt[p], cnt[p-1], ... の中で最初に 0 であるものを探す(cnt[0] == 0 であるから,これが番兵となってこの for 文は必ず止まる */
      if (p - q == 5 || (p == 13 && q == 9 && cnt[1] == 1)) {  /* ストレートである条件 */
        printf("straight\n");
      } else {
        printf("no pair\n");
      }
      break;
    }
  }
}