本講義では 2 通のレポートで評価します。 レポートは A4 縦の様式で PDF 形式で作成して下さい。 またプログラムは C 言語で作成しなさい。
課題1で使用した構造体 RESULT を前提とした、 次の構造体 NODE に関する関数を作成する。
typedef struct{
char* country;
int medal[3];
} RESULT;
typedef struct node {
RESULT result;
struct node* left;
struct node* right;
} NODE;
ヘッダファイルなどはまとめて後ろに示してある。
なお、レポートにおいては、作成したプログラムの説明が必須であるが、課 題1で作成した関数に関しては説明する必要は無い。
以下のプログラム mondai21.c において、以下の問に答えなさい
#include "kadai2.h"
#include "data.h"
int main(void){
int i;
for(i=0;i<=4;i++){
data[i].left=&data[2*i+1];
data[i].right=&data[2*i+2];
}
printtree(&data[0]);
return 0;
}
printree を呼び出す直前の各データ構造を図で示しなさい。 構造体は、漢字の目のように長方形を区切った図として表しなさい。 また、 left, right などのポインターに関しては、長方形の中央を始点と し、実際に指している構造体を表す長方形を指すように矢印を書きなさい。
NODE型の番地を受け取り、それを二分木として、木の左から順に RESULT 型の値を表示する関数
void printtree(NODE*)
を作成せよ。
但し、ファイル名を printtree.c とする。
また、RESULT 型の値を表示するのに課題1で作成した関数を使用して良い
これと、mondai21.c, kadai2.h, kadai1.h, data.h を結合して実行し、出 力結果を示せ。
CZE: 0 0 1 RUS: 2 0 1 GBR: 1 0 0 CHN: 0 2 1 ETH: 0 1 0 USA: 0 1 0 KEN: 0 0 1 AUS: 1 0 0 TTO: 1 0 0 IRL: 0 0 1 FIN: 0 1 0
2つの RESULT 型の値、 a,b を受け取った時、以下の条件に従って値を返す
int compresult(RESULT a, RESULT b)
を作成しなさい。
但し、 string.h を include するものとする。
これと、以下のプログラム, kadai1.h, data.h を結合して実行し、出 力結果を示せ。
#include <stdio.h>
#include "kadai2.h"
#include "data.h"
int main(void){
int i,j,res;
char out;
for(i=0;data[i].result.country!=0;i++){
printf("%s ",data[i].result.country);
}
printf("\n");
for(i=0;data[i].result.country!=0;i++){
for(j=0;data[j].result.country!=0;j++){
res=compresult(data[i].result,data[j].result);
if(res==0){
out='0';
}else if(res>0){
out='+';
}else{
out='-';
}
printf(" %c ",out);
}
printresult(&data[i].result);
}
return 0;
}
AUS CHN IRL RUS USA TTO FIN CZE GBR ETH KEN 0 + + - + - + + - + + AUS: 1 0 0 - 0 + - + - + + - + + CHN: 0 2 1 - - 0 - - - - + - - - IRL: 0 0 1 + + + 0 + + + + + + + RUS: 2 0 1 - - + - 0 - + + - + + USA: 0 1 0 + + + - + 0 + + + + + TTO: 1 0 0 - - + - - - 0 + - + + FIN: 0 1 0 - - - - - - - 0 - - - CZE: 0 0 1 + + + - + - + + 0 + + GBR: 1 0 0 - - + - - - - + - 0 + ETH: 0 1 0 - - + - - - - + - - 0 KEN: 0 0 1
compresult 関数により大小を決定する
NODE 型の順序木の根のポインターの番地と、
RESULT 型の値を受け取って、
順序木に値を追加する関数
NODE* addtree(NODE **t, RESULT r)
を作成しなさい。
なお、 addtree の戻り値は付け加えたノードへのポインターで、メモリが
確保できなかった時は NULL を返すものとします。
これと、下記のテストプログラム, kadai2.h, printtree, compresult, deltree (後述)を結合して実行し、 出力結果を示せ。
#include <stdio.h>
#include <stdlib.h>
#include "kadai2.h"
#include "data.h"
int main(void){
NODE* root=NULL;
int i;
for(i=0;data[i].result.country!=0;i++){
printresult(&data[i].result);
if(addtree(&root,data[i].result) == NULL){
fprintf(stderr,"メモリーエラー\n");
return 1;
}
}
printf("-----\n");
printtree(root);
deltree(root);
return 0;
}
AUS: 1 0 0 CHN: 0 2 1 IRL: 0 0 1 RUS: 2 0 1 USA: 0 1 0 TTO: 1 0 0 FIN: 0 1 0 CZE: 0 0 1 GBR: 1 0 0 ETH: 0 1 0 KEN: 0 0 1 ----- CZE: 0 0 1 IRL: 0 0 1 KEN: 0 0 1 ETH: 0 1 0 FIN: 0 1 0 USA: 0 1 0 CHN: 0 2 1 AUS: 1 0 0 GBR: 1 0 0 TTO: 1 0 0 RUS: 2 0 1
#include "kadai1.h"
typedef struct node {
RESULT result;
struct node* left;
struct node* right;
} NODE;
void printtree(NODE* list);
int compresult(RESULT a, RESULT b);
NODE* addtree(NODE **t, RESULT r);
void deltree(NODE* node);
NODE data[]={{{"AUS",{1, 0, 0}}},
{{"CHN",{0, 2, 1}}},
{{"IRL",{0, 0, 1}}},
{{"RUS",{2, 0, 1}}},
{{"USA",{0, 1, 0}}},
{{"TTO",{1, 0, 0}}},
{{"FIN",{0, 1, 0}}},
{{"CZE",{0, 0, 1}}},
{{"GBR",{1, 0, 0}}},
{{"ETH",{0, 1, 0}}},
{{"KEN",{0, 0, 1}}},
{{0}}};
CC=gcc
mondai21.exe: mondai21.o printresult.o printtree.o
$(CC) -o $@ $^
mondai22.exe: mondai22.o printresult.o compresult.o
$(CC) -o $@ $^
mondai23.exe: mondai23.o printresult.o printtree.o compresult.o addtree.o deltree.o
$(CC) -o $@ $^
clean:
rm *.o *.exe
mondai21.o: kadai1.h kadai2.h data.h
mondai22.o: kadai1.h kadai2.h data.h
mondai23.o: kadai1.h kadai2.h data.h
printtree.o: kadai1.h kadai2.h
compresult.o: kadai1.h
addtree.o: kadai1.h kadai2.h
deltree.o: kadai1.h kadai2.h
printresult.o: kadai1.h
#include <stdlib.h>
#include "kadai2.h"
void deltree(NODE* node){
if(node==NULL){
return;
}
deltree(node->left);
deltree(node->right);
free(node);
}
解答法として、分割コンパイルによる別ファイルにプログラムを書く方 法と、下記のテストプログラムに関数を追記する方法の二通りがあるが、 どちらでも良い。 プログラムの解説は、自分で作成した関数について行うこと。 こちらで提供したテストプログラムの説明は基本的には不要である。 但し、自分で作成した関数を説明するのに必要な内容には言及すること。
なお、レポートは締め切り後も提出できます。 同じファイル名で複数のバージョンが存在できます。 締め切り内に採点可能なレポートがある場合は、最も締切に近いものだけを採 点します。 締め切り内に有効なレポートがない場合、最も新しいレポートを遅れレポー トとして減点の上採点します。
次の構造体の配列に関する関数を作成する。
typedef struct{
char* country;
int medal[3];
} RESULT;
なお、country メンバーには、ISO 3166-1で規定されている3文字の国名コー ドが入ることが想定されている(現在249種類)。 また、配列の番兵は、country メンバーに NULL を入れることとする。
RESULT型の番地を受け取り、一行表示する関数
void printresult(RESULT*)
を作成せよ。
但し、ファイル名を printresult.c とする。
これと、下記のテストプログラム, kadai1.h を結合して実行し、出 力結果を示せ。
#include "kadai1.h"
#define NULL 0
int main(void){
RESULT resultlist[]={{"JPN",{1,2,3}},{"USA",{2,3,4}},{"GBR",{3,4,5}},{NULL}};
RESULT *r;
for(r=resultlist;r->country!=NULL;r++){
printresult(r);
}
return 0;
}
JPN: 1 2 3 USA: 2 3 4 GBR: 3 4 5
番兵で終端するRESULT型の配列の先頭番地と、文字列の番地を受け取り、
番兵までの範囲で文字列が一致する要素を見つけ、その要素への番地を返す
RESULT* searchresult(RESULT*,char*)
を作成せよ。なお、未発見の場合、番兵の入っている要素の番地を返すとする。
この関数のファイル名を searchresult.c とする。
なお、作成するにあたって、 string.h をインクルードし、 strcmp 関数
を使用しても良い。
これと、下記のテストプログラム,printresult, kadai1.h を結合して実行し、出 力結果を示せ。
#include <stdio.h>
#include "kadai1.h"
typedef struct {
char* country;
int index;
} DATA;
int main(void){
RESULT result[]={{"JPN",{1,2,3}},{"USA",{2,3,4}},{"GBR",{3,4,5}},{NULL}};
char* country[]={"GBR","USA","JPN","USR",NULL};
char** p;
RESULT* r;
for(p=country; *p!=NULL; p++){
r=searchresult(result, *p);
if(r->country!=NULL){
printresult(r);
}else{
printf("無し\n");
}
}
return 0;
}
GBR: 3 4 5 USA: 2 3 4 JPN: 1 2 3 無し
番兵で終端するRESULT型の配列の先頭番地と、文字列の番地と、添字(0,1,2 のい
ずれかの数)を受け取り、
与えた文字列を含む要素の中の指定した添字のmedal配列の要素を 1増やす関数
RESULT* addresult(RESULT*,char*,int)
を作成せよ。
なお、文字列が発見できない時は、番兵の部分に、文字列をstrdup関数に
よりコピーし、さらに、medal 配列をすべて0で初期化した後、指定した
添字の要素のみ 1 とする。
また、関数の戻り値は、1増やした要素の番地とする。
これを作成する際に、searchresult を呼び出して良い。
なお、ファイル名を addresult.c とする。
strdup 関数は string.h ヘッダファイルをインクルードして使用する (Visual Studio では _strdup)。 引数に文字列を指定すると、その文字列をコピーして先頭番地を返す。 但し、コピーに失敗した場合に NULL を返すが、この課題においてはコピー は必ず成功すると仮定し、失敗の処理を省略して良い。
これと、下記のテストプログラム,printresult, searchresult, kadai1.h に加え、あとで示す printresultlist, clearresult も結合して実行し、出 力結果を示せ。
#include <stdio.h>
#include "kadai1.h"
typedef struct {
char* country;
int index;
} DATA;
int main(void){
RESULT resultlist[250]={{NULL,{100,200,300}},{NULL,{9,8,7}}};
DATA data[]={{"JPN",0},{"USA",1},{"GBR",2},
{"USA",0},{"JPN",1},{"USR",2},
{"GBR",0},{"USA",1},{"GBR",2},{NULL}};
DATA *p;
for(p=data; p->country!=NULL; p++){
printresult(addresult(resultlist, p->country, p->index));
}
printf("-------\n");
printresultlist(resultlist);
clearresult(resultlist);
return 0;
}
JPN: 1 0 0 USA: 0 1 0 GBR: 0 0 1 USA: 1 1 0 JPN: 1 1 0 USR: 0 0 1 GBR: 1 0 1 USA: 1 2 0 GBR: 1 0 2 ------- JPN: 1 1 0 USA: 1 2 0 GBR: 1 0 2 USR: 0 0 1
文字列4つからなる要素を持つ、文字列の二次元配列を考える。
4つの内訳は、「イベント名、1位の国、2位の国、3位の国」である。
4つの文字列の配列を受け取って、RESULT の配列に対して、各国のメダル
数 medal を加算する関数 void inc(RESULT* char**)
を作成せよ。
これは、addresult を呼び出して良い。
なお、ファイル名を inc.c とする。
これと、下記のテストプログラム,addresult,printresult, searchresult, kadai1.h に加え、あとで示す printresultlist, clearresult も結合して実行し、出 力結果を示せ。
#include <stdio.h>
#include "kadai1.h"
int main(void){
RESULT resultlist[250]={0};
char* events[][4]= {
{"50 Kilometres Race Walk men","AUS","CHN","IRL"},
{"20 Kilometres Race Walk women","RUS","CHN","CHN"},
{"High Jump women","RUS","USA","RUS"},
{"Javelin Throw men","TTO","FIN","CZE"},
{"5000 Metres men","GBR","ETH","KEN"},
{NULL}
};
char* (*p)[4];
int i;
for(p=events;(*p)[0]!=NULL;p++){
inc(resultlist,*p);
}
printresultlist(resultlist);
clearresult(resultlist);
return 0;
}
AUS: 1 0 0 CHN: 0 2 1 IRL: 0 0 1 RUS: 2 0 1 USA: 0 1 0 TTO: 1 0 0 FIN: 0 1 0 CZE: 0 0 1 GBR: 1 0 0 ETH: 0 1 0 KEN: 0 0 1
typedef struct {
char* country;
int medal[3];
} RESULT;
void printresultlist(RESULT* r);
RESULT* addresult(RESULT* r, char* c, int i);
void clearresult(RESULT* r);
RESULT* searchresult(RESULT* resultlist, char* name);
void printresult(RESULT* r);
void inc(RESULT* list, char** p);
#include <stdio.h>
#include "kadai1.h"
void printresultlist(RESULT* r){
for(; r->country!=NULL; r++){
printresult(r);
}
}
#include <stdlib.h>
#include "kadai1.h"
void clearresult(RESULT *r){
while(r->country!=NULL){
free(r->country);
r->country=NULL;
r++;
}
}
$(CC) -o $@ $^
の $(CC) の前には TAB 記号が一つ
だけ入っていることに注意する。これが空白記号に置き換わっていると動作しない。
CC=gcc
mondai14.exe: mondai14.o printresult.o addresult.o clearresult.o searchresult.o printresultlist.o inc.o
$(CC) -o $@ $^
mondai13.exe: mondai13.o printresult.o addresult.o clearresult.o searchresult.o printresultlist.o
$(CC) -o $@ $^
mondai12.exe: mondai12.o searchresult.o printresult.o clearresult.o
$(CC) -o $@ $^
mondai11.exe: mondai11.o printresult.o
$(CC) -o $@ $^
clean:
rm *.o *.exe
mondai13.o: kadai1.h
mondai12.o: kadai1.h
mondai11.o: kadai1.h
clearresult.o: kadai1.h
addresult.o: kadai1.h
addresult.o: searchresult.c
printresult.o: kadai1.h
searchresult.o: kadai1.h
printresultlist.o: kadai1.h
printresultlist.o: printresult.c
inc.o: kadai1.h
inc.o: addresult.c
なお、写したと思われるほど酷似したレポートが複数提出された場合、原著が どれかの調査を行わず、抽選で一通のレポートのみを評価 の対象とし、他は提出済みの不合格レポートとして再提出は課しません。 自分で意図せずに他人にコピーされてしまった場合も同様ですので、レポート の取り扱いについては十分に注意して下さい。