応用課題:基本情報技術者試験問題に挑戦(2)

 基本情報技術者のC言語問題を、もう一つ解いてみましょう。今回は、平成19年春季試験の午後 問10(改題)の問題を扱います。

 …… 

【平成19年秋季 午後 問06(改)】

次のCプログラムの説明及びプログラムを読んで,設問1,2に答えよ。

〔プログラムの説明〕

リーグ戦の勝敗表を出力するプログラムである。

(1) 勝敗表の出力例を図1に示す。

    チーム名   勝ち  負け     勝率
    Giants       86    43    0.667
    Tigers       55    75    0.423
    Dragons      75    53    0.586
    Swallows     68    65    0.511
    Baystars     46    85    0.351
    Carp         61    71    0.462
  図1 勝敗表の出力例

(2) チームの勝敗情報は構造体 RECORD で表現する。引き分けはないものとする。

typedef struct {               /* 勝敗情報 */
    char   name[MAX_LENGTH+1]; /* チーム名 */
    int    wins;               /* 勝ち数 */
    int    losses;             /* 負け数 */
    double average;            /* 勝率 */
} RECORD;

全チームの勝敗情報は構造体 RECORD の配列 team に格納されている。

チーム名,勝ち数,負け数はあらかじめ格納されているが,勝率は格納されていない。

(3) プログラム中の関数 calcAverage と print の仕様は次のとおりである。

void calcAverage()
機能:全チームの勝率を計算し,それぞれのメンバ average に格納する。 試合数が0の場合,勝率は 0.0 とする。

void print()


    機能:勝敗表を出力する。

〔プログラム1〕

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TEAMNUM 6              /* チーム数 */
#define MAX_LENGTH 10          /* チーム名の長さの上限 */

typedef struct {               /* 勝敗情報 */
    char   name[MAX_LENGTH+1]; /* チーム名 */
    int    wins;               /* 勝ち数 */
    int    losses;             /* 負け数 */
    double average;            /* 勝率 */
} RECORD;

RECORD team[TEAMNUM];

void insertTeams(){
    strcpy(team[0].name, "Giants");
    strcpy(team[1].name, "Tigers");
    strcpy(team[2].name, "Dragons");
    strcpy(team[3].name, "Swallows");
    strcpy(team[4].name, "Baystars");
    strcpy(team[5].name, "Carp");
    team[0].wins = 86;
    team[1].wins = 55;
    team[2].wins = 75;
    team[3].wins = 68;
    team[4].wins = 46;
    team[5].wins = 61;
    team[0].losses = 43;
    team[1].losses = 75;
    team[2].losses = 53;
    team[3].losses = 65;
    team[4].losses = 85;
    team[5].losses = 71;
}

void calcAverage(){
    int i, total;
    insertTeams();
    for(i = 0; i < TEAMNUM; i++){
        total = team[i].wins + team[i].losses;
        if(【 a 】){
            team[i].average = 0.0;
        } else {
            【 b 】;
        }
    }
}

void print(){
    int i;
    calcAverage();
    printf("チーム名   勝ち  負け     勝率\n");
    for(i = 0; i < TEAMNUM; i++){
        printf("%-10s %4d  %4d    %5.3f\n",
               team[i].name, team[i].wins, team[i].losses, team[i].average);
    }
}

int main(int argc, const char * argv[])
{
    
    // insert code here...
    print();
    
    return 0;
}

設問1 プログラム1中の 【 a 】, 【 b 】 に入れる正しい答えを, 解答群の中から選べ。

【 a 】に関する解答群

ア team[i].average < 0.0    イ team[i].average > 0.0

ウ total != 0          エ total == 0

【 b 】に関する解答群

ア (double)team[i].average = team[i].wins / total

イ team[i].average = (double)(team[i].wins / total)

ウ team[i].average = (double)team[i].wins / total

エ team[i].average = team[i].wins / total

設問2 順位の項目を加え,勝率の高いチームから順に出力する関数 printRank を作成した。 勝率順の勝敗表の出力例を図2に示す。勝率が同率の場合は同順位とする。

    順位   チーム名   勝ち  負け     勝率
    1      Giants       86    43    0.667
    2      Dragons      75    53    0.586
    3      Swallows     68    65    0.511
    4      Carp         61    71    0.462
    5      Tigers       55    75    0.423
    6      Baystars     46    85    0.351

    図2 勝率順の勝敗表の出力例

処理手順は次のとおりである。

(1) TEAMNUM 個の要素をもつポインタ配列 pTeam を定義する。

(2) 配列 team の各要素のアドレスを,先頭要素から順番に配列 pTeam の各要素に格納する。 これによって要素番号iに対応するチームの勝率 team[i].average は,pTeam[i]->average に よっても参照できる。

(3) 配列 team 自体を整列する代わりに配列 pTeam の要素を整列して,勝率順の勝敗表を出力する。

次の関数があらかじめ定義されているものとする。

void sort(RECORD *pTeam[TEAMNUM])


     機能:TEAMNUM 個の要素からなり,各要素が RECORD 型の構造体へのポインタで ある配列 pTeam の要素を, 勝率の降順になるように整列する。

プログラム2中の 【 c 】, 【 d 】, 【 e 】 に入れる正しい答えを,解答群の中から選べ。

〔プログラム2〕

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TEAMNUM 6              /* チーム数 */
#define MAX_LENGTH 10          /* チーム名の長さの上限 */

typedef struct {               /* 勝敗情報 */
    char   name[MAX_LENGTH+1]; /* チーム名 */
    int    wins;               /* 勝ち数 */
    int    losses;             /* 負け数 */
    double average;            /* 勝率 */
} RECORD;

RECORD team[TEAMNUM];

void insertTeams(){
    strcpy(team[0].name, "Giants");
    strcpy(team[1].name, "Tigers");
    strcpy(team[2].name, "Dragons");
    strcpy(team[3].name, "Swallows");
    strcpy(team[4].name, "Baystars");
    strcpy(team[5].name, "Carp");
    team[0].wins = 86;
    team[1].wins = 55;
    team[2].wins = 75;
    team[3].wins = 68;
    team[4].wins = 46;
    team[5].wins = 61;
    team[0].losses = 43;
    team[1].losses = 75;
    team[2].losses = 53;
    team[3].losses = 65;
    team[4].losses = 85;
    team[5].losses = 71;
}

void calcAverage(){
    int i, total;
    insertTeams();
    for(i = 0; i < TEAMNUM; i++){
        total = team[i].wins + team[i].losses;
        if(total == 0){
            team[i].average = 0.0;
        } else {
            team[i].average = (double)team[i].wins / total;
        }
    }
}

int compare(const void *c1, const void *c2){
    RECORD team1 = *(RECORD *)c1;
    RECORD team2 = *(RECORD *)c2;
    
    double tmp1 = team1.average;
    double tmp2 = team2.average;
    
    return 1000 * (tmp2 - tmp1);
}

void printRank(){
    int i;
    int rank = 1;
    RECORD *pTeam[TEAMNUM];
    
    calcAverage();
    qsort(team, TEAMNUM, sizeof(RECORD), compare);
    for(i = 0; i < TEAMNUM; i++){
        【 c 】;
    }
    
    printf("順位   チーム名   勝ち  負け     勝率\n");
    for(i = 0; i < TEAMNUM; i++){
        if(i > 0){
            【 d 】;
        }
        printf("%1d      %-10s %4d  %4d    %5.3f\n", rank,
               【 e 】->name,
               【 e 】->wins,
               【 e 】->losses,
               【 e 】->average);
    }
}

int main(int argc, const char * argv[])
{
    
    // insert code here...
    printRank();
    
    return 0;
}

【 c 】 に関する解答群

ア pTeam[i] = &team[i]     イ pTeam[i] = team

ウ team[i] = **pTeam       エ team[i] = *pTeam[i]

【 d 】 に関する解答群

ア rank++        イ rank = i

ウ rank = i + 1     エ rank = TEAMNUM - (i + 1)

オ rank = TEAMNUM - i 

【 e 】 に関する解答群

ア (&team[i])     イ (&team[rank])

ウ pTeam[i]       エ pTeam[rank]

 …… 

 この問題は、考え方も重要ですが、ポインタと構造体に慣れていれば正解しやすい問題となっています。この問題も、ひとつずつ、じっくり見ていきましょう。まず設問1のa。aのif文の直前でtotalの計算をしています。totalは、勝ち数と負け数の和です。この計算の後に、とある条件判定をし、それによっては、そのチームのaverage(勝率)を0.0にするというものです。選択肢の中で勝率を0.0にすべきものとしてはアとエがありますが、アのような勝率がマイナスになることはありえないので、この場合は、答えはエの「total == 0」となります。1試合も行っていない場合は勝率を0.0にする、ということです。

 続いて、b。勝率の計算をします。勝率は、(勝ち数)÷(勝ち数+負け数)です。よって、答えはウの「team[i].average = (double)team[i].wins / total」です。

 引き続き、設問2に入ります。まず、c。これは、ポインタの使い方を問う問題です。ソートされた配列teamの各要素を構造体pTeamに入れます。その方法として適しているのはアの「pTeam[i] = &team[i]」です。

 設問2のd。変数rankの中身を更新し、下のprintf文で順位として表示したいというものです。既に順番通りに並んでいるので、for文のカウンターであるiを用いたいのですが、イのように「rank = i」ですと、iが0から始まっているので、このままではダメです。iに1を足したものをrankに入れるべきです。よって答えはウの「rank = i + 1」です。

 設問2のe。構造体の扱い方を問う問題です。よって、答えはウの「pTeam[i]」が入ります。各内容を当てはめたプログラムを作成、実行し、表示内容が設問のとおりとなっているか確認して下さい。基本情報技術者試験の実際の問題(多少は改題しましたが)なので、少々難しいかもしれませんが、よく基礎を復習すれば出来る問題をピックアップしたつもりです。ぜひ、復習しましょう。尚、通常レベルのC言語試験の問題を解く場合、言語知識の他に、考え方である「アルゴリズム」の知識が必要になりますので、注意して下さい。

 C言語講座は以上です。充実したC言語ライフが送れるようになることを、お祈りいたします。

■スポンサーリンク

このページの先頭へ